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 // Android-added: this method is from OpenJDK 17. Made public hidden to access it 310 // in ZipFile w/o SharedSecrets. 311 /** 312 * Creates a ZipEntry suitable for the given ZipFile. 313 * @hide 314 */ entryFor(String name)315 public JarEntry entryFor(String name) { 316 return new JarFileEntry(name); 317 } 318 319 private class JarFileEntry extends JarEntry { JarFileEntry(ZipEntry ze)320 JarFileEntry(ZipEntry ze) { 321 super(ze); 322 } 323 324 // Android-added: imported from OpenJDK 17 for entryFor(String) support. JarFileEntry(String name)325 JarFileEntry(String name) { 326 super(name); 327 } 328 getAttributes()329 public Attributes getAttributes() throws IOException { 330 Manifest man = JarFile.this.getManifest(); 331 if (man != null) { 332 return man.getAttributes(getName()); 333 } else { 334 return null; 335 } 336 } getCertificates()337 public Certificate[] getCertificates() { 338 try { 339 maybeInstantiateVerifier(); 340 } catch (IOException e) { 341 throw new RuntimeException(e); 342 } 343 if (certs == null && jv != null) { 344 certs = jv.getCerts(JarFile.this, this); 345 } 346 return certs == null ? null : certs.clone(); 347 } getCodeSigners()348 public CodeSigner[] getCodeSigners() { 349 try { 350 maybeInstantiateVerifier(); 351 } catch (IOException e) { 352 throw new RuntimeException(e); 353 } 354 if (signers == null && jv != null) { 355 signers = jv.getCodeSigners(JarFile.this, this); 356 } 357 return signers == null ? null : signers.clone(); 358 } 359 } 360 361 /* 362 * Ensures that the JarVerifier has been created if one is 363 * necessary (i.e., the jar appears to be signed.) This is done as 364 * a quick check to avoid processing of the manifest for unsigned 365 * jars. 366 */ maybeInstantiateVerifier()367 private void maybeInstantiateVerifier() throws IOException { 368 if (jv != null) { 369 return; 370 } 371 372 if (verify) { 373 // BEGIN Android-changed: use OpenJDK 17 implementation. 374 /* 375 String[] names = getMetaInfEntryNames(); 376 if (names != null) { 377 for (int i = 0; i < names.length; i++) { 378 String name = names[i].toUpperCase(Locale.ENGLISH); 379 if (name.endsWith(".DSA") || 380 name.endsWith(".RSA") || 381 name.endsWith(".EC") || 382 name.endsWith(".SF")) { 383 // Assume since we found a signature-related file 384 // that the jar is signed and that we therefore 385 // need a JarVerifier and Manifest 386 getManifest(); 387 return; 388 } 389 } 390 } 391 // No signature-related files; don't instantiate a 392 // verifier 393 verify = false; 394 */ 395 // Gets the manifest name, but only if there are 396 // signature-related files. If so we can assume 397 // that the jar is signed and that we therefore 398 // need a JarVerifier and Manifest 399 // String name = JUZFA.getManifestName(this, true); 400 String name = getManifestName(true); 401 if (name != null) { 402 getManifest(); 403 return; 404 } 405 // No signature-related files; don't instantiate a 406 // verifier 407 verify = false; 408 // END Android-changed: use OpenJDK 17 implementation. 409 } 410 } 411 412 413 /* 414 * Initializes the verifier object by reading all the manifest 415 * entries and passing them to the verifier. 416 */ initializeVerifier()417 private void initializeVerifier() { 418 ManifestEntryVerifier mev = null; 419 420 // Verify "META-INF/" entries... 421 // BEGIN Android-changed: use OpenJDK17 implementation. 422 /* 423 try { 424 String[] names = getMetaInfEntryNames(); 425 if (names != null) { 426 for (int i = 0; i < names.length; i++) { 427 String uname = names[i].toUpperCase(Locale.ENGLISH); 428 if (MANIFEST_NAME.equals(uname) 429 || SignatureFileVerifier.isBlockOrSF(uname)) { 430 JarEntry e = getJarEntry(names[i]); 431 if (e == null) { 432 throw new JarException("corrupted jar file"); 433 } 434 if (mev == null) { 435 mev = new ManifestEntryVerifier 436 (getManifestFromReference()); 437 } 438 byte[] b = getBytes(e); 439 if (b != null && b.length > 0) { 440 jv.beginEntry(e, mev); 441 jv.update(b.length, b, 0, b.length, mev); 442 jv.update(-1, null, 0, 0, mev); 443 } 444 } 445 } 446 } 447 } catch (IOException ex) { 448 // if we had an error parsing any blocks, just 449 // treat the jar file as being unsigned 450 jv = null; 451 verify = false; 452 if (JarVerifier.debug != null) { 453 JarVerifier.debug.println("jarfile parsing error!"); 454 ex.printStackTrace(); 455 } 456 } 457 */ 458 try { 459 List<String> names = getManifestAndSignatureRelatedFiles(); 460 for (String name : names) { 461 JarEntry e = getJarEntry(name); 462 byte[] b; 463 if (e == null) { 464 throw new JarException("corrupted jar file"); 465 } 466 if (mev == null) { 467 // BEGIN Android-changed: ManifestEntryVerifier(Manifest, String) is not imported yet. 468 /* 469 mev = new ManifestEntryVerifier 470 (getManifestFromReference()), jv.manifestName); 471 */ 472 mev = new ManifestEntryVerifier(getManifestFromReference()); 473 // END Android-changed: ManifestEntryVerifier(Manifest, String) is not imported yet. 474 } 475 if (name.equalsIgnoreCase(MANIFEST_NAME)) { 476 b = jv.manifestRawBytes; 477 } else { 478 b = getBytes(e); 479 } 480 if (b != null && b.length > 0) { 481 jv.beginEntry(e, mev); 482 jv.update(b.length, b, 0, b.length, mev); 483 jv.update(-1, null, 0, 0, mev); 484 } 485 } 486 } catch (IOException | IllegalArgumentException ex) { 487 // if we had an error parsing any blocks, just 488 // treat the jar file as being unsigned 489 jv = null; 490 verify = false; 491 if (JarVerifier.debug != null) { 492 JarVerifier.debug.println("jarfile parsing error!"); 493 ex.printStackTrace(); 494 } 495 } 496 // END Android-changed: use OpenJDK17 implementation. 497 498 // if after initializing the verifier we have nothing 499 // signed, we null it out. 500 501 if (jv != null) { 502 503 jv.doneWithMeta(); 504 if (JarVerifier.debug != null) { 505 JarVerifier.debug.println("done with meta!"); 506 } 507 508 if (jv.nothingToVerify()) { 509 if (JarVerifier.debug != null) { 510 JarVerifier.debug.println("nothing to verify!"); 511 } 512 jv = null; 513 verify = false; 514 } 515 } 516 } 517 518 /* 519 * Reads all the bytes for a given entry. Used to process the 520 * META-INF files. 521 */ getBytes(ZipEntry ze)522 private byte[] getBytes(ZipEntry ze) throws IOException { 523 try (InputStream is = super.getInputStream(ze)) { 524 return IOUtils.readFully(is, (int)ze.getSize(), true); 525 } 526 } 527 528 /** 529 * Returns an input stream for reading the contents of the specified 530 * zip file entry. 531 * @param ze the zip file entry 532 * @return an input stream for reading the contents of the specified 533 * zip file entry 534 * @throws ZipException if a zip file format error has occurred 535 * @throws IOException if an I/O error has occurred 536 * @throws SecurityException if any of the jar file entries 537 * are incorrectly signed. 538 * @throws IllegalStateException 539 * may be thrown if the jar file has been closed 540 */ getInputStream(ZipEntry ze)541 public synchronized InputStream getInputStream(ZipEntry ze) 542 throws IOException 543 { 544 maybeInstantiateVerifier(); 545 if (jv == null) { 546 return super.getInputStream(ze); 547 } 548 if (!jvInitialized) { 549 initializeVerifier(); 550 jvInitialized = true; 551 // could be set to null after a call to 552 // initializeVerifier if we have nothing to 553 // verify 554 if (jv == null) 555 return super.getInputStream(ze); 556 } 557 558 // wrap a verifier stream around the real stream 559 return new JarVerifier.VerifierStream( 560 getManifestFromReference(), 561 ze instanceof JarFileEntry ? 562 (JarEntry) ze : getJarEntry(ze.getName()), 563 super.getInputStream(ze), 564 jv); 565 } 566 567 // Statics for hand-coded Boyer-Moore search 568 private static final char[] CLASSPATH_CHARS = {'c','l','a','s','s','-','p','a','t','h'}; 569 // The bad character shift for "class-path" 570 private static final int[] CLASSPATH_LASTOCC; 571 // The good suffix shift for "class-path" 572 private static final int[] CLASSPATH_OPTOSFT; 573 574 static { 575 CLASSPATH_LASTOCC = new int[128]; 576 CLASSPATH_OPTOSFT = new int[10]; 577 CLASSPATH_LASTOCC[(int)'c'] = 1; 578 CLASSPATH_LASTOCC[(int)'l'] = 2; 579 CLASSPATH_LASTOCC[(int)'s'] = 5; 580 CLASSPATH_LASTOCC[(int)'-'] = 6; 581 CLASSPATH_LASTOCC[(int)'p'] = 7; 582 CLASSPATH_LASTOCC[(int)'a'] = 8; 583 CLASSPATH_LASTOCC[(int)'t'] = 9; 584 CLASSPATH_LASTOCC[(int)'h'] = 10; 585 for (int i=0; i<9; i++) 586 CLASSPATH_OPTOSFT[i] = 10; 587 CLASSPATH_OPTOSFT[9]=1; 588 } 589 590 // BEGIN Android-changed: Fix JarFile to be thread safe. http://b/27826114 591 // A volatile field might also work instead of synchronized. http://b/81505612 592 // private JarEntry getManEntry() { getManEntry()593 private synchronized JarEntry getManEntry() { 594 // END Android-changed: Fix JarFile to be thread safe. http://b/27826114 595 // BEGIN Android-changed: use OpenJDK 17 implementation. 596 /* 597 if (manEntry == null) { 598 // First look up manifest entry using standard name 599 manEntry = getJarEntry(MANIFEST_NAME); 600 if (manEntry == null) { 601 // If not found, then iterate through all the "META-INF/" 602 // entries to find a match. 603 String[] names = getMetaInfEntryNames(); 604 if (names != null) { 605 for (int i = 0; i < names.length; i++) { 606 if (MANIFEST_NAME.equals( 607 names[i].toUpperCase(Locale.ENGLISH))) { 608 manEntry = getJarEntry(names[i]); 609 break; 610 } 611 } 612 } 613 } 614 } 615 */ 616 if (manEntry == null) { 617 // The manifest entry position is resolved during 618 // initialization 619 String name = getManifestName(false); 620 if (name != null) { 621 this.manEntry = (JarEntry)super.getEntry(name); 622 } 623 } 624 // END Android-changed: use OpenJDK 17 implementation. 625 return manEntry; 626 } 627 628 /** 629 * Returns {@code true} iff this JAR file has a manifest with the 630 * Class-Path attribute 631 * @hide 632 */ 633 // Android-changed: Make hasClassPathAttribute() @hide public, for internal use. 634 // Used by URLClassPath.JarLoader. 635 // boolean hasClassPathAttribute() throws IOException { hasClassPathAttribute()636 public boolean hasClassPathAttribute() throws IOException { 637 checkForSpecialAttributes(); 638 return hasClassPathAttribute; 639 } 640 641 /** 642 * Returns true if the pattern {@code src} is found in {@code b}. 643 * The {@code lastOcc} and {@code optoSft} arrays are the precomputed 644 * bad character and good suffix shifts. 645 */ match(char[] src, byte[] b, int[] lastOcc, int[] optoSft)646 private boolean match(char[] src, byte[] b, int[] lastOcc, int[] optoSft) { 647 int len = src.length; 648 int last = b.length - len; 649 int i = 0; 650 next: 651 while (i<=last) { 652 for (int j=(len-1); j>=0; j--) { 653 char c = (char) b[i+j]; 654 c = (((c-'A')|('Z'-c)) >= 0) ? (char)(c + 32) : c; 655 if (c != src[j]) { 656 i += Math.max(j + 1 - lastOcc[c&0x7F], optoSft[j]); 657 continue next; 658 } 659 } 660 return true; 661 } 662 return false; 663 } 664 665 /** 666 * On first invocation, check if the JAR file has the Class-Path 667 * attribute. A no-op on subsequent calls. 668 */ checkForSpecialAttributes()669 private void checkForSpecialAttributes() throws IOException { 670 if (hasCheckedSpecialAttributes) return; 671 // Android-changed: Special handling of well-known .jar files specific to OpenJDK. 672 // if (!isKnownNotToHaveSpecialAttributes()) { 673 { 674 JarEntry manEntry = getManEntry(); 675 if (manEntry != null) { 676 byte[] b = getBytes(manEntry); 677 if (match(CLASSPATH_CHARS, b, CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT)) 678 hasClassPathAttribute = true; 679 } 680 } 681 hasCheckedSpecialAttributes = true; 682 } 683 684 685 // Android-removed: Special handling of well-known .jar files specific to OpenJDK. 686 /* 687 private static String javaHome; 688 private static volatile String[] jarNames; 689 private boolean isKnownNotToHaveSpecialAttributes() { 690 // Optimize away even scanning of manifest for jar files we 691 // deliver which don't have a class-path attribute. If one of 692 // these jars is changed to include such an attribute this code 693 // must be changed. 694 if (javaHome == null) { 695 javaHome = AccessController.doPrivileged( 696 new GetPropertyAction("java.home")); 697 } 698 if (jarNames == null) { 699 String[] names = new String[11]; 700 String fileSep = File.separator; 701 int i = 0; 702 names[i++] = fileSep + "rt.jar"; 703 names[i++] = fileSep + "jsse.jar"; 704 names[i++] = fileSep + "jce.jar"; 705 names[i++] = fileSep + "charsets.jar"; 706 names[i++] = fileSep + "dnsns.jar"; 707 names[i++] = fileSep + "zipfs.jar"; 708 names[i++] = fileSep + "localedata.jar"; 709 names[i++] = fileSep = "cldrdata.jar"; 710 names[i++] = fileSep + "sunjce_provider.jar"; 711 names[i++] = fileSep + "sunpkcs11.jar"; 712 names[i++] = fileSep + "sunec.jar"; 713 jarNames = names; 714 } 715 716 String name = getName(); 717 String localJavaHome = javaHome; 718 if (name.startsWith(localJavaHome)) { 719 String[] names = jarNames; 720 for (int i = 0; i < names.length; i++) { 721 if (name.endsWith(names[i])) { 722 return true; 723 } 724 } 725 } 726 return false; 727 } 728 */ 729 730 // Android-removed: Unused method ensureInitialization(). 731 /* 732 private synchronized void ensureInitialization() { 733 try { 734 maybeInstantiateVerifier(); 735 } catch (IOException e) { 736 throw new RuntimeException(e); 737 } 738 if (jv != null && !jvInitialized) { 739 initializeVerifier(); 740 jvInitialized = true; 741 } 742 } 743 */ 744 newEntry(ZipEntry ze)745 JarEntry newEntry(ZipEntry ze) { 746 return new JarFileEntry(ze); 747 } 748 749 // Android-removed: Unused methods entryNames(), entries2(). 750 /* 751 Enumeration<String> entryNames(CodeSource[] cs) { 752 ensureInitialization(); 753 if (jv != null) { 754 return jv.entryNames(this, cs); 755 } 756 757 /* 758 * JAR file has no signed content. Is there a non-signing 759 * code source? 760 * 761 boolean includeUnsigned = false; 762 for (int i = 0; i < cs.length; i++) { 763 if (cs[i].getCodeSigners() == null) { 764 includeUnsigned = true; 765 break; 766 } 767 } 768 if (includeUnsigned) { 769 return unsignedEntryNames(); 770 } else { 771 return new Enumeration<String>() { 772 773 public boolean hasMoreElements() { 774 return false; 775 } 776 777 public String nextElement() { 778 throw new NoSuchElementException(); 779 } 780 }; 781 } 782 } 783 784 /** 785 * Returns an enumeration of the zip file entries 786 * excluding internal JAR mechanism entries and including 787 * signed entries missing from the ZIP directory. 788 * 789 Enumeration<JarEntry> entries2() { 790 ensureInitialization(); 791 if (jv != null) { 792 return jv.entries2(this, super.entries()); 793 } 794 795 // screen out entries which are never signed 796 final Enumeration<? extends ZipEntry> enum_ = super.entries(); 797 return new Enumeration<JarEntry>() { 798 799 ZipEntry entry; 800 801 public boolean hasMoreElements() { 802 if (entry != null) { 803 return true; 804 } 805 while (enum_.hasMoreElements()) { 806 ZipEntry ze = enum_.nextElement(); 807 if (JarVerifier.isSigningRelated(ze.getName())) { 808 continue; 809 } 810 entry = ze; 811 return true; 812 } 813 return false; 814 } 815 816 public JarFileEntry nextElement() { 817 if (hasMoreElements()) { 818 ZipEntry ze = entry; 819 entry = null; 820 return new JarFileEntry(ze); 821 } 822 throw new NoSuchElementException(); 823 } 824 }; 825 } 826 827 CodeSource[] getCodeSources(URL url) { 828 ensureInitialization(); 829 if (jv != null) { 830 return jv.getCodeSources(this, url); 831 } 832 833 /* 834 * JAR file has no signed content. Is there a non-signing 835 * code source? 836 * 837 Enumeration<String> unsigned = unsignedEntryNames(); 838 if (unsigned.hasMoreElements()) { 839 return new CodeSource[]{JarVerifier.getUnsignedCS(url)}; 840 } else { 841 return null; 842 } 843 } 844 845 private Enumeration<String> unsignedEntryNames() { 846 final Enumeration<JarEntry> entries = entries(); 847 return new Enumeration<String>() { 848 849 String name; 850 851 /* 852 * Grab entries from ZIP directory but screen out 853 * metadata. 854 * 855 public boolean hasMoreElements() { 856 if (name != null) { 857 return true; 858 } 859 while (entries.hasMoreElements()) { 860 String value; 861 ZipEntry e = entries.nextElement(); 862 value = e.getName(); 863 if (e.isDirectory() || JarVerifier.isSigningRelated(value)) { 864 continue; 865 } 866 name = value; 867 return true; 868 } 869 return false; 870 } 871 872 public String nextElement() { 873 if (hasMoreElements()) { 874 String value = name; 875 name = null; 876 return value; 877 } 878 throw new NoSuchElementException(); 879 } 880 }; 881 } 882 883 CodeSource getCodeSource(URL url, String name) { 884 ensureInitialization(); 885 if (jv != null) { 886 if (jv.eagerValidation) { 887 CodeSource cs = null; 888 JarEntry je = getJarEntry(name); 889 if (je != null) { 890 cs = jv.getCodeSource(url, this, je); 891 } else { 892 cs = jv.getCodeSource(url, name); 893 } 894 return cs; 895 } else { 896 return jv.getCodeSource(url, name); 897 } 898 } 899 900 return JarVerifier.getUnsignedCS(url); 901 } 902 903 void setEagerValidation(boolean eager) { 904 try { 905 maybeInstantiateVerifier(); 906 } catch (IOException e) { 907 throw new RuntimeException(e); 908 } 909 if (jv != null) { 910 jv.setEagerValidation(eager); 911 } 912 } 913 914 List<Object> getManifestDigests() { 915 ensureInitialization(); 916 if (jv != null) { 917 return jv.getManifestDigests(); 918 } 919 return new ArrayList<Object>(); 920 } 921 */ 922 } 923