1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.util.jar; 28 29 import java.io.*; 30 import java.lang.ref.SoftReference; 31 import java.util.*; 32 import java.util.stream.Stream; 33 import java.util.stream.StreamSupport; 34 import java.util.zip.*; 35 import java.security.CodeSigner; 36 import java.security.cert.Certificate; 37 import java.security.AccessController; 38 import sun.misc.IOUtils; 39 import sun.security.action.GetPropertyAction; 40 import sun.security.util.ManifestEntryVerifier; 41 import sun.security.util.SignatureFileVerifier; 42 43 /** 44 * The <code>JarFile</code> class is used to read the contents of a jar file 45 * from any file that can be opened with <code>java.io.RandomAccessFile</code>. 46 * It extends the class <code>java.util.zip.ZipFile</code> with support 47 * for reading an optional <code>Manifest</code> entry. The 48 * <code>Manifest</code> can be used to specify meta-information about the 49 * jar file and its entries. 50 * 51 * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor 52 * or method in this class will cause a {@link NullPointerException} to be 53 * thrown. 54 * 55 * If the verify flag is on when opening a signed jar file, the content of the 56 * file is verified against its signature embedded inside the file. Please note 57 * that the verification process does not include validating the signer's 58 * certificate. A caller should inspect the return value of 59 * {@link JarEntry#getCodeSigners()} to further determine if the signature 60 * can be trusted. 61 * 62 * @author David Connelly 63 * @see Manifest 64 * @see java.util.zip.ZipFile 65 * @see java.util.jar.JarEntry 66 * @since 1.2 67 */ 68 public 69 class JarFile extends ZipFile { 70 // Android-changed: Hold the Manifest via a hard reference. http://b/28692091 71 // private SoftReference<Manifest> manRef; 72 private Manifest manifest; 73 private JarEntry manEntry; 74 private JarVerifier jv; 75 private boolean jvInitialized; 76 private boolean verify; 77 78 // indicates if Class-Path attribute present (only valid if hasCheckedSpecialAttributes true) 79 private boolean hasClassPathAttribute; 80 // true if manifest checked for special attributes 81 private volatile boolean hasCheckedSpecialAttributes; 82 83 // Android-removed: SharedSecrets.setJavaUtilJarAccess 84 /* 85 // Set up JavaUtilJarAccess in SharedSecrets 86 static { 87 SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl()); 88 } 89 */ 90 91 /** 92 * The JAR manifest file name. 93 */ 94 public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF"; 95 96 /** 97 * Creates a new <code>JarFile</code> to read from the specified 98 * file <code>name</code>. The <code>JarFile</code> will be verified if 99 * it is signed. 100 * @param name the name of the jar file to be opened for reading 101 * @throws IOException if an I/O error has occurred 102 * @throws SecurityException if access to the file is denied 103 * by the SecurityManager 104 */ JarFile(String name)105 public JarFile(String name) throws IOException { 106 this(new File(name), true, ZipFile.OPEN_READ); 107 } 108 109 /** 110 * Creates a new <code>JarFile</code> to read from the specified 111 * file <code>name</code>. 112 * @param name the name of the jar file to be opened for reading 113 * @param verify whether or not to verify the jar file if 114 * it is signed. 115 * @throws IOException if an I/O error has occurred 116 * @throws SecurityException if access to the file is denied 117 * by the SecurityManager 118 */ JarFile(String name, boolean verify)119 public JarFile(String name, boolean verify) throws IOException { 120 this(new File(name), verify, ZipFile.OPEN_READ); 121 } 122 123 /** 124 * Creates a new <code>JarFile</code> to read from the specified 125 * <code>File</code> object. The <code>JarFile</code> will be verified if 126 * it is signed. 127 * @param file the jar file to be opened for reading 128 * @throws IOException if an I/O error has occurred 129 * @throws SecurityException if access to the file is denied 130 * by the SecurityManager 131 */ JarFile(File file)132 public JarFile(File file) throws IOException { 133 this(file, true, ZipFile.OPEN_READ); 134 } 135 136 137 /** 138 * Creates a new <code>JarFile</code> to read from the specified 139 * <code>File</code> object. 140 * @param file the jar file to be opened for reading 141 * @param verify whether or not to verify the jar file if 142 * it is signed. 143 * @throws IOException if an I/O error has occurred 144 * @throws SecurityException if access to the file is denied 145 * by the SecurityManager. 146 */ JarFile(File file, boolean verify)147 public JarFile(File file, boolean verify) throws IOException { 148 this(file, verify, ZipFile.OPEN_READ); 149 } 150 151 152 // Android-changed: Use of the hidden constructor with a new argument for zip path validation. 153 /** 154 * Creates a new <code>JarFile</code> to read from the specified 155 * <code>File</code> object in the specified mode. The mode argument 156 * must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>. 157 * 158 * @param file the jar file to be opened for reading 159 * @param verify whether or not to verify the jar file if 160 * it is signed. 161 * @param mode the mode in which the file is to be opened 162 * @throws IOException if an I/O error has occurred 163 * @throws IllegalArgumentException 164 * if the <tt>mode</tt> argument is invalid 165 * @throws SecurityException if access to the file is denied 166 * by the SecurityManager 167 * @since 1.3 168 */ JarFile(File file, boolean verify, int mode)169 public JarFile(File file, boolean verify, int mode) throws IOException { 170 this(file, /* enableZipPathValidator */ true, verify, mode); 171 } 172 173 // Android-added: New hidden constructor with an argument for zip path validation and verify. 174 /** @hide */ JarFile(String name, boolean enableZipPathValidator, boolean verify)175 public JarFile(String name, boolean enableZipPathValidator, boolean verify) throws IOException { 176 this(new File(name), enableZipPathValidator, verify, ZipFile.OPEN_READ); 177 } 178 179 // Android-added: New hidden constructor with all available arguments. 180 /** @hide */ JarFile(File file, boolean enableZipPathValidator, boolean verify, int mode)181 public JarFile(File file, boolean enableZipPathValidator, boolean verify, int mode) throws 182 IOException { 183 super(file, mode, enableZipPathValidator); 184 this.verify = verify; 185 } 186 187 /** 188 * Returns the jar file manifest, or <code>null</code> if none. 189 * 190 * @return the jar file manifest, or <code>null</code> if none 191 * 192 * @throws IllegalStateException 193 * may be thrown if the jar file has been closed 194 * @throws IOException if an I/O error has occurred 195 */ getManifest()196 public Manifest getManifest() throws IOException { 197 return getManifestFromReference(); 198 } 199 200 // BEGIN Android-changed: Fix JarFile to be thread safe. http://b/27826114 201 // A volatile field might also work instead of synchronized. http://b/81505612 202 // private Manifest getManifestFromReference() throws IOException { getManifestFromReference()203 private synchronized Manifest getManifestFromReference() throws IOException { 204 // END Android-changed: Fix JarFile to be thread safe. http://b/27826114 205 // Android-changed: Hold the Manifest via a hard reference. http://b/28692091 206 // Manifest man = manRef != null ? manRef.get() : null; 207 Manifest man = manifest; 208 if (man == null) { 209 210 JarEntry manEntry = getManEntry(); 211 212 // If found then load the manifest 213 if (manEntry != null) { 214 if (verify) { 215 byte[] b = getBytes(manEntry); 216 man = new Manifest(new ByteArrayInputStream(b)); 217 if (!jvInitialized) { 218 jv = new JarVerifier(manEntry.getName(), b); 219 } 220 } else { 221 man = new Manifest(super.getInputStream(manEntry)); 222 } 223 // Android-changed: Hold the Manifest via a hard reference. http://b/28692091 224 // manRef = new SoftReference<>(man); 225 manifest = man; 226 } 227 } 228 return man; 229 } 230 getMetaInfEntryNames()231 private native String[] getMetaInfEntryNames(); 232 233 /** 234 * Returns the <code>JarEntry</code> for the given entry name or 235 * <code>null</code> if not found. 236 * 237 * @param name the jar file entry name 238 * @return the <code>JarEntry</code> for the given entry name or 239 * <code>null</code> if not found. 240 * 241 * @throws IllegalStateException 242 * may be thrown if the jar file has been closed 243 * 244 * @see java.util.jar.JarEntry 245 */ getJarEntry(String name)246 public JarEntry getJarEntry(String name) { 247 return (JarEntry)getEntry(name); 248 } 249 250 /** 251 * Returns the <code>ZipEntry</code> for the given entry name or 252 * <code>null</code> if not found. 253 * 254 * @param name the jar file entry name 255 * @return the <code>ZipEntry</code> for the given entry name or 256 * <code>null</code> if not found 257 * 258 * @throws IllegalStateException 259 * may be thrown if the jar file has been closed 260 * 261 * @see java.util.zip.ZipEntry 262 */ getEntry(String name)263 public ZipEntry getEntry(String name) { 264 ZipEntry ze = super.getEntry(name); 265 if (ze != null) { 266 return new JarFileEntry(ze); 267 } 268 return null; 269 } 270 271 private class JarEntryIterator implements Enumeration<JarEntry>, 272 Iterator<JarEntry> 273 { 274 final Enumeration<? extends ZipEntry> e = JarFile.super.entries(); 275 hasNext()276 public boolean hasNext() { 277 return e.hasMoreElements(); 278 } 279 next()280 public JarEntry next() { 281 ZipEntry ze = e.nextElement(); 282 return new JarFileEntry(ze); 283 } 284 hasMoreElements()285 public boolean hasMoreElements() { 286 return hasNext(); 287 } 288 nextElement()289 public JarEntry nextElement() { 290 return next(); 291 } 292 } 293 294 /** 295 * Returns an enumeration of the zip file entries. 296 */ entries()297 public Enumeration<JarEntry> entries() { 298 return new JarEntryIterator(); 299 } 300 301 @Override stream()302 public Stream<JarEntry> stream() { 303 return StreamSupport.stream(Spliterators.spliterator( 304 new JarEntryIterator(), size(), 305 Spliterator.ORDERED | Spliterator.DISTINCT | 306 Spliterator.IMMUTABLE | Spliterator.NONNULL), false); 307 } 308 309 private class JarFileEntry extends JarEntry { JarFileEntry(ZipEntry ze)310 JarFileEntry(ZipEntry ze) { 311 super(ze); 312 } getAttributes()313 public Attributes getAttributes() throws IOException { 314 Manifest man = JarFile.this.getManifest(); 315 if (man != null) { 316 return man.getAttributes(getName()); 317 } else { 318 return null; 319 } 320 } getCertificates()321 public Certificate[] getCertificates() { 322 try { 323 maybeInstantiateVerifier(); 324 } catch (IOException e) { 325 throw new RuntimeException(e); 326 } 327 if (certs == null && jv != null) { 328 certs = jv.getCerts(JarFile.this, this); 329 } 330 return certs == null ? null : certs.clone(); 331 } getCodeSigners()332 public CodeSigner[] getCodeSigners() { 333 try { 334 maybeInstantiateVerifier(); 335 } catch (IOException e) { 336 throw new RuntimeException(e); 337 } 338 if (signers == null && jv != null) { 339 signers = jv.getCodeSigners(JarFile.this, this); 340 } 341 return signers == null ? null : signers.clone(); 342 } 343 } 344 345 /* 346 * Ensures that the JarVerifier has been created if one is 347 * necessary (i.e., the jar appears to be signed.) This is done as 348 * a quick check to avoid processing of the manifest for unsigned 349 * jars. 350 */ maybeInstantiateVerifier()351 private void maybeInstantiateVerifier() throws IOException { 352 if (jv != null) { 353 return; 354 } 355 356 if (verify) { 357 String[] names = getMetaInfEntryNames(); 358 if (names != null) { 359 for (int i = 0; i < names.length; i++) { 360 String name = names[i].toUpperCase(Locale.ENGLISH); 361 if (name.endsWith(".DSA") || 362 name.endsWith(".RSA") || 363 name.endsWith(".EC") || 364 name.endsWith(".SF")) { 365 // Assume since we found a signature-related file 366 // that the jar is signed and that we therefore 367 // need a JarVerifier and Manifest 368 getManifest(); 369 return; 370 } 371 } 372 } 373 // No signature-related files; don't instantiate a 374 // verifier 375 verify = false; 376 } 377 } 378 379 380 /* 381 * Initializes the verifier object by reading all the manifest 382 * entries and passing them to the verifier. 383 */ initializeVerifier()384 private void initializeVerifier() { 385 ManifestEntryVerifier mev = null; 386 387 // Verify "META-INF/" entries... 388 try { 389 String[] names = getMetaInfEntryNames(); 390 if (names != null) { 391 for (int i = 0; i < names.length; i++) { 392 String uname = names[i].toUpperCase(Locale.ENGLISH); 393 if (MANIFEST_NAME.equals(uname) 394 || SignatureFileVerifier.isBlockOrSF(uname)) { 395 JarEntry e = getJarEntry(names[i]); 396 if (e == null) { 397 throw new JarException("corrupted jar file"); 398 } 399 if (mev == null) { 400 mev = new ManifestEntryVerifier 401 (getManifestFromReference()); 402 } 403 byte[] b = getBytes(e); 404 if (b != null && b.length > 0) { 405 jv.beginEntry(e, mev); 406 jv.update(b.length, b, 0, b.length, mev); 407 jv.update(-1, null, 0, 0, mev); 408 } 409 } 410 } 411 } 412 } catch (IOException ex) { 413 // if we had an error parsing any blocks, just 414 // treat the jar file as being unsigned 415 jv = null; 416 verify = false; 417 if (JarVerifier.debug != null) { 418 JarVerifier.debug.println("jarfile parsing error!"); 419 ex.printStackTrace(); 420 } 421 } 422 423 // if after initializing the verifier we have nothing 424 // signed, we null it out. 425 426 if (jv != null) { 427 428 jv.doneWithMeta(); 429 if (JarVerifier.debug != null) { 430 JarVerifier.debug.println("done with meta!"); 431 } 432 433 if (jv.nothingToVerify()) { 434 if (JarVerifier.debug != null) { 435 JarVerifier.debug.println("nothing to verify!"); 436 } 437 jv = null; 438 verify = false; 439 } 440 } 441 } 442 443 /* 444 * Reads all the bytes for a given entry. Used to process the 445 * META-INF files. 446 */ getBytes(ZipEntry ze)447 private byte[] getBytes(ZipEntry ze) throws IOException { 448 try (InputStream is = super.getInputStream(ze)) { 449 return IOUtils.readFully(is, (int)ze.getSize(), true); 450 } 451 } 452 453 /** 454 * Returns an input stream for reading the contents of the specified 455 * zip file entry. 456 * @param ze the zip file entry 457 * @return an input stream for reading the contents of the specified 458 * zip file entry 459 * @throws ZipException if a zip file format error has occurred 460 * @throws IOException if an I/O error has occurred 461 * @throws SecurityException if any of the jar file entries 462 * are incorrectly signed. 463 * @throws IllegalStateException 464 * may be thrown if the jar file has been closed 465 */ getInputStream(ZipEntry ze)466 public synchronized InputStream getInputStream(ZipEntry ze) 467 throws IOException 468 { 469 maybeInstantiateVerifier(); 470 if (jv == null) { 471 return super.getInputStream(ze); 472 } 473 if (!jvInitialized) { 474 initializeVerifier(); 475 jvInitialized = true; 476 // could be set to null after a call to 477 // initializeVerifier if we have nothing to 478 // verify 479 if (jv == null) 480 return super.getInputStream(ze); 481 } 482 483 // wrap a verifier stream around the real stream 484 return new JarVerifier.VerifierStream( 485 getManifestFromReference(), 486 ze instanceof JarFileEntry ? 487 (JarEntry) ze : getJarEntry(ze.getName()), 488 super.getInputStream(ze), 489 jv); 490 } 491 492 // Statics for hand-coded Boyer-Moore search 493 private static final char[] CLASSPATH_CHARS = {'c','l','a','s','s','-','p','a','t','h'}; 494 // The bad character shift for "class-path" 495 private static final int[] CLASSPATH_LASTOCC; 496 // The good suffix shift for "class-path" 497 private static final int[] CLASSPATH_OPTOSFT; 498 499 static { 500 CLASSPATH_LASTOCC = new int[128]; 501 CLASSPATH_OPTOSFT = new int[10]; 502 CLASSPATH_LASTOCC[(int)'c'] = 1; 503 CLASSPATH_LASTOCC[(int)'l'] = 2; 504 CLASSPATH_LASTOCC[(int)'s'] = 5; 505 CLASSPATH_LASTOCC[(int)'-'] = 6; 506 CLASSPATH_LASTOCC[(int)'p'] = 7; 507 CLASSPATH_LASTOCC[(int)'a'] = 8; 508 CLASSPATH_LASTOCC[(int)'t'] = 9; 509 CLASSPATH_LASTOCC[(int)'h'] = 10; 510 for (int i=0; i<9; i++) 511 CLASSPATH_OPTOSFT[i] = 10; 512 CLASSPATH_OPTOSFT[9]=1; 513 } 514 515 // BEGIN Android-changed: Fix JarFile to be thread safe. http://b/27826114 516 // A volatile field might also work instead of synchronized. http://b/81505612 517 // private JarEntry getManEntry() { getManEntry()518 private synchronized JarEntry getManEntry() { 519 // END Android-changed: Fix JarFile to be thread safe. http://b/27826114 520 if (manEntry == null) { 521 // First look up manifest entry using standard name 522 manEntry = getJarEntry(MANIFEST_NAME); 523 if (manEntry == null) { 524 // If not found, then iterate through all the "META-INF/" 525 // entries to find a match. 526 String[] names = getMetaInfEntryNames(); 527 if (names != null) { 528 for (int i = 0; i < names.length; i++) { 529 if (MANIFEST_NAME.equals( 530 names[i].toUpperCase(Locale.ENGLISH))) { 531 manEntry = getJarEntry(names[i]); 532 break; 533 } 534 } 535 } 536 } 537 } 538 return manEntry; 539 } 540 541 /** 542 * Returns {@code true} iff this JAR file has a manifest with the 543 * Class-Path attribute 544 * @hide 545 */ 546 // Android-changed: Make hasClassPathAttribute() @hide public, for internal use. 547 // Used by URLClassPath.JarLoader. 548 // boolean hasClassPathAttribute() throws IOException { hasClassPathAttribute()549 public boolean hasClassPathAttribute() throws IOException { 550 checkForSpecialAttributes(); 551 return hasClassPathAttribute; 552 } 553 554 /** 555 * Returns true if the pattern {@code src} is found in {@code b}. 556 * The {@code lastOcc} and {@code optoSft} arrays are the precomputed 557 * bad character and good suffix shifts. 558 */ match(char[] src, byte[] b, int[] lastOcc, int[] optoSft)559 private boolean match(char[] src, byte[] b, int[] lastOcc, int[] optoSft) { 560 int len = src.length; 561 int last = b.length - len; 562 int i = 0; 563 next: 564 while (i<=last) { 565 for (int j=(len-1); j>=0; j--) { 566 char c = (char) b[i+j]; 567 c = (((c-'A')|('Z'-c)) >= 0) ? (char)(c + 32) : c; 568 if (c != src[j]) { 569 i += Math.max(j + 1 - lastOcc[c&0x7F], optoSft[j]); 570 continue next; 571 } 572 } 573 return true; 574 } 575 return false; 576 } 577 578 /** 579 * On first invocation, check if the JAR file has the Class-Path 580 * attribute. A no-op on subsequent calls. 581 */ checkForSpecialAttributes()582 private void checkForSpecialAttributes() throws IOException { 583 if (hasCheckedSpecialAttributes) return; 584 // Android-changed: Special handling of well-known .jar files specific to OpenJDK. 585 // if (!isKnownNotToHaveSpecialAttributes()) { 586 { 587 JarEntry manEntry = getManEntry(); 588 if (manEntry != null) { 589 byte[] b = getBytes(manEntry); 590 if (match(CLASSPATH_CHARS, b, CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT)) 591 hasClassPathAttribute = true; 592 } 593 } 594 hasCheckedSpecialAttributes = true; 595 } 596 597 598 // Android-removed: Special handling of well-known .jar files specific to OpenJDK. 599 /* 600 private static String javaHome; 601 private static volatile String[] jarNames; 602 private boolean isKnownNotToHaveSpecialAttributes() { 603 // Optimize away even scanning of manifest for jar files we 604 // deliver which don't have a class-path attribute. If one of 605 // these jars is changed to include such an attribute this code 606 // must be changed. 607 if (javaHome == null) { 608 javaHome = AccessController.doPrivileged( 609 new GetPropertyAction("java.home")); 610 } 611 if (jarNames == null) { 612 String[] names = new String[11]; 613 String fileSep = File.separator; 614 int i = 0; 615 names[i++] = fileSep + "rt.jar"; 616 names[i++] = fileSep + "jsse.jar"; 617 names[i++] = fileSep + "jce.jar"; 618 names[i++] = fileSep + "charsets.jar"; 619 names[i++] = fileSep + "dnsns.jar"; 620 names[i++] = fileSep + "zipfs.jar"; 621 names[i++] = fileSep + "localedata.jar"; 622 names[i++] = fileSep = "cldrdata.jar"; 623 names[i++] = fileSep + "sunjce_provider.jar"; 624 names[i++] = fileSep + "sunpkcs11.jar"; 625 names[i++] = fileSep + "sunec.jar"; 626 jarNames = names; 627 } 628 629 String name = getName(); 630 String localJavaHome = javaHome; 631 if (name.startsWith(localJavaHome)) { 632 String[] names = jarNames; 633 for (int i = 0; i < names.length; i++) { 634 if (name.endsWith(names[i])) { 635 return true; 636 } 637 } 638 } 639 return false; 640 } 641 */ 642 643 // Android-removed: Unused method ensureInitialization(). 644 /* 645 private synchronized void ensureInitialization() { 646 try { 647 maybeInstantiateVerifier(); 648 } catch (IOException e) { 649 throw new RuntimeException(e); 650 } 651 if (jv != null && !jvInitialized) { 652 initializeVerifier(); 653 jvInitialized = true; 654 } 655 } 656 */ 657 newEntry(ZipEntry ze)658 JarEntry newEntry(ZipEntry ze) { 659 return new JarFileEntry(ze); 660 } 661 662 // Android-removed: Unused methods entryNames(), entries2(). 663 /* 664 Enumeration<String> entryNames(CodeSource[] cs) { 665 ensureInitialization(); 666 if (jv != null) { 667 return jv.entryNames(this, cs); 668 } 669 670 /* 671 * JAR file has no signed content. Is there a non-signing 672 * code source? 673 * 674 boolean includeUnsigned = false; 675 for (int i = 0; i < cs.length; i++) { 676 if (cs[i].getCodeSigners() == null) { 677 includeUnsigned = true; 678 break; 679 } 680 } 681 if (includeUnsigned) { 682 return unsignedEntryNames(); 683 } else { 684 return new Enumeration<String>() { 685 686 public boolean hasMoreElements() { 687 return false; 688 } 689 690 public String nextElement() { 691 throw new NoSuchElementException(); 692 } 693 }; 694 } 695 } 696 697 /** 698 * Returns an enumeration of the zip file entries 699 * excluding internal JAR mechanism entries and including 700 * signed entries missing from the ZIP directory. 701 * 702 Enumeration<JarEntry> entries2() { 703 ensureInitialization(); 704 if (jv != null) { 705 return jv.entries2(this, super.entries()); 706 } 707 708 // screen out entries which are never signed 709 final Enumeration<? extends ZipEntry> enum_ = super.entries(); 710 return new Enumeration<JarEntry>() { 711 712 ZipEntry entry; 713 714 public boolean hasMoreElements() { 715 if (entry != null) { 716 return true; 717 } 718 while (enum_.hasMoreElements()) { 719 ZipEntry ze = enum_.nextElement(); 720 if (JarVerifier.isSigningRelated(ze.getName())) { 721 continue; 722 } 723 entry = ze; 724 return true; 725 } 726 return false; 727 } 728 729 public JarFileEntry nextElement() { 730 if (hasMoreElements()) { 731 ZipEntry ze = entry; 732 entry = null; 733 return new JarFileEntry(ze); 734 } 735 throw new NoSuchElementException(); 736 } 737 }; 738 } 739 740 CodeSource[] getCodeSources(URL url) { 741 ensureInitialization(); 742 if (jv != null) { 743 return jv.getCodeSources(this, url); 744 } 745 746 /* 747 * JAR file has no signed content. Is there a non-signing 748 * code source? 749 * 750 Enumeration<String> unsigned = unsignedEntryNames(); 751 if (unsigned.hasMoreElements()) { 752 return new CodeSource[]{JarVerifier.getUnsignedCS(url)}; 753 } else { 754 return null; 755 } 756 } 757 758 private Enumeration<String> unsignedEntryNames() { 759 final Enumeration<JarEntry> entries = entries(); 760 return new Enumeration<String>() { 761 762 String name; 763 764 /* 765 * Grab entries from ZIP directory but screen out 766 * metadata. 767 * 768 public boolean hasMoreElements() { 769 if (name != null) { 770 return true; 771 } 772 while (entries.hasMoreElements()) { 773 String value; 774 ZipEntry e = entries.nextElement(); 775 value = e.getName(); 776 if (e.isDirectory() || JarVerifier.isSigningRelated(value)) { 777 continue; 778 } 779 name = value; 780 return true; 781 } 782 return false; 783 } 784 785 public String nextElement() { 786 if (hasMoreElements()) { 787 String value = name; 788 name = null; 789 return value; 790 } 791 throw new NoSuchElementException(); 792 } 793 }; 794 } 795 796 CodeSource getCodeSource(URL url, String name) { 797 ensureInitialization(); 798 if (jv != null) { 799 if (jv.eagerValidation) { 800 CodeSource cs = null; 801 JarEntry je = getJarEntry(name); 802 if (je != null) { 803 cs = jv.getCodeSource(url, this, je); 804 } else { 805 cs = jv.getCodeSource(url, name); 806 } 807 return cs; 808 } else { 809 return jv.getCodeSource(url, name); 810 } 811 } 812 813 return JarVerifier.getUnsignedCS(url); 814 } 815 816 void setEagerValidation(boolean eager) { 817 try { 818 maybeInstantiateVerifier(); 819 } catch (IOException e) { 820 throw new RuntimeException(e); 821 } 822 if (jv != null) { 823 jv.setEagerValidation(eager); 824 } 825 } 826 827 List<Object> getManifestDigests() { 828 ensureInitialization(); 829 if (jv != null) { 830 return jv.getManifestDigests(); 831 } 832 return new ArrayList<Object>(); 833 } 834 */ 835 } 836