1 /* 2 * Copyright (c) 1997, 2019, 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.util.jar; 27 28 import java.io.*; 29 import java.net.URL; 30 import java.util.*; 31 import java.security.*; 32 import java.security.cert.CertificateException; 33 import java.util.zip.ZipEntry; 34 35 import jdk.internal.util.jar.JarIndex; 36 import sun.security.util.ManifestDigester; 37 import sun.security.util.ManifestEntryVerifier; 38 import sun.security.util.SignatureFileVerifier; 39 import sun.security.util.Debug; 40 41 /** 42 * 43 * @author Roland Schemers 44 */ 45 class JarVerifier { 46 47 /* Are we debugging ? */ 48 static final Debug debug = Debug.getInstance("jar"); 49 50 /* a table mapping names to code signers, for jar entries that have 51 had their actual hashes verified */ 52 private Hashtable<String, CodeSigner[]> verifiedSigners; 53 54 /* a table mapping names to code signers, for jar entries that have 55 passed the .SF/.DSA/.EC -> MANIFEST check */ 56 private Hashtable<String, CodeSigner[]> sigFileSigners; 57 58 /* a hash table to hold .SF bytes */ 59 private Hashtable<String, byte[]> sigFileData; 60 61 /** "queue" of pending PKCS7 blocks that we couldn't parse 62 * until we parsed the .SF file */ 63 private ArrayList<SignatureFileVerifier> pendingBlocks; 64 65 /* cache of CodeSigner objects */ 66 private ArrayList<CodeSigner[]> signerCache; 67 68 /* Are we parsing a block? */ 69 private boolean parsingBlockOrSF = false; 70 71 /* Are we done parsing META-INF entries? */ 72 private boolean parsingMeta = true; 73 74 /* Are there are files to verify? */ 75 private boolean anyToVerify = true; 76 77 /* The output stream to use when keeping track of files we are interested 78 in */ 79 private ByteArrayOutputStream baos; 80 81 /** The ManifestDigester object */ 82 private volatile ManifestDigester manDig; 83 84 /** the bytes for the manDig object */ 85 byte manifestRawBytes[] = null; 86 87 /** controls eager signature validation */ 88 boolean eagerValidation; 89 90 /** makes code source singleton instances unique to us */ 91 private Object csdomain = new Object(); 92 93 /** collect -DIGEST-MANIFEST values for blacklist */ 94 private List<Object> manifestDigests; 95 96 public JarVerifier(byte rawBytes[]) { 97 manifestRawBytes = rawBytes; 98 sigFileSigners = new Hashtable<>(); 99 verifiedSigners = new Hashtable<>(); 100 sigFileData = new Hashtable<>(11); 101 pendingBlocks = new ArrayList<>(); 102 baos = new ByteArrayOutputStream(); 103 manifestDigests = new ArrayList<>(); 104 } 105 106 /** 107 * This method scans to see which entry we're parsing and 108 * keeps various state information depending on what type of 109 * file is being parsed. 110 */ 111 public void beginEntry(JarEntry je, ManifestEntryVerifier mev) 112 throws IOException 113 { 114 if (je == null) 115 return; 116 117 if (debug != null) { 118 debug.println("beginEntry "+je.getName()); 119 } 120 121 String name = je.getName(); 122 123 /* 124 * Assumptions: 125 * 1. The manifest should be the first entry in the META-INF directory. 126 * 2. The .SF/.DSA/.EC files follow the manifest, before any normal entries 127 * 3. Any of the following will throw a SecurityException: 128 * a. digest mismatch between a manifest section and 129 * the SF section. 130 * b. digest mismatch between the actual jar entry and the manifest 131 */ 132 133 if (parsingMeta) { 134 String uname = name.toUpperCase(Locale.ENGLISH); 135 if ((uname.startsWith("META-INF/") || 136 uname.startsWith("/META-INF/"))) { 137 138 if (je.isDirectory()) { 139 mev.setEntry(null, je); 140 return; 141 } 142 143 if (uname.equals(JarFile.MANIFEST_NAME) || 144 uname.equals(JarIndex.INDEX_NAME)) { 145 return; 146 } 147 148 if (SignatureFileVerifier.isBlockOrSF(uname)) { 149 /* We parse only DSA, RSA or EC PKCS7 blocks. */ 150 parsingBlockOrSF = true; 151 baos.reset(); 152 mev.setEntry(null, je); 153 return; 154 } 155 156 // If a META-INF entry is not MF or block or SF, they should 157 // be normal entries. According to 2 above, no more block or 158 // SF will appear. Let's doneWithMeta. 159 } 160 } 161 162 if (parsingMeta) { 163 doneWithMeta(); 164 } 165 166 if (je.isDirectory()) { 167 mev.setEntry(null, je); 168 return; 169 } 170 171 // be liberal in what you accept. If the name starts with ./, remove 172 // it as we internally canonicalize it with out the ./. 173 if (name.startsWith("./")) 174 name = name.substring(2); 175 176 // be liberal in what you accept. If the name starts with /, remove 177 // it as we internally canonicalize it with out the /. 178 if (name.startsWith("/")) 179 name = name.substring(1); 180 181 // only set the jev object for entries that have a signature 182 // (either verified or not) 183 if (!name.equals(JarFile.MANIFEST_NAME)) { 184 if (sigFileSigners.get(name) != null || 185 verifiedSigners.get(name) != null) { 186 mev.setEntry(name, je); 187 return; 188 } 189 } 190 191 // don't compute the digest for this entry 192 mev.setEntry(null, je); 193 194 return; 195 } 196 197 /** 198 * update a single byte. 199 */ 200 201 public void update(int b, ManifestEntryVerifier mev) 202 throws IOException 203 { 204 if (b != -1) { 205 if (parsingBlockOrSF) { 206 baos.write(b); 207 } else { 208 mev.update((byte)b); 209 } 210 } else { 211 processEntry(mev); 212 } 213 } 214 215 /** 216 * update an array of bytes. 217 */ 218 219 public void update(int n, byte[] b, int off, int len, 220 ManifestEntryVerifier mev) 221 throws IOException 222 { 223 if (n != -1) { 224 if (parsingBlockOrSF) { 225 baos.write(b, off, n); 226 } else { 227 mev.update(b, off, n); 228 } 229 } else { 230 processEntry(mev); 231 } 232 } 233 234 /** 235 * called when we reach the end of entry in one of the read() methods. 236 */ 237 private void processEntry(ManifestEntryVerifier mev) 238 throws IOException 239 { 240 if (!parsingBlockOrSF) { 241 JarEntry je = mev.getEntry(); 242 if ((je != null) && (je.signers == null)) { 243 je.signers = mev.verify(verifiedSigners, sigFileSigners); 244 je.certs = mapSignersToCertArray(je.signers); 245 } 246 } else { 247 248 try { 249 parsingBlockOrSF = false; 250 251 if (debug != null) { 252 debug.println("processEntry: processing block"); 253 } 254 255 String uname = mev.getEntry().getName() 256 .toUpperCase(Locale.ENGLISH); 257 258 if (uname.endsWith(".SF")) { 259 String key = uname.substring(0, uname.length()-3); 260 byte bytes[] = baos.toByteArray(); 261 // add to sigFileData in case future blocks need it 262 sigFileData.put(key, bytes); 263 // check pending blocks, we can now process 264 // anyone waiting for this .SF file 265 for (SignatureFileVerifier sfv : pendingBlocks) { 266 if (sfv.needSignatureFile(key)) { 267 if (debug != null) { 268 debug.println( 269 "processEntry: processing pending block"); 270 } 271 272 sfv.setSignatureFile(bytes); 273 sfv.process(sigFileSigners, manifestDigests); 274 } 275 } 276 return; 277 } 278 279 // now we are parsing a signature block file 280 281 String key = uname.substring(0, uname.lastIndexOf('.')); 282 283 if (signerCache == null) 284 signerCache = new ArrayList<>(); 285 286 if (manDig == null) { 287 synchronized(manifestRawBytes) { 288 if (manDig == null) { 289 manDig = new ManifestDigester(manifestRawBytes); 290 manifestRawBytes = null; 291 } 292 } 293 } 294 295 SignatureFileVerifier sfv = 296 new SignatureFileVerifier(signerCache, 297 manDig, uname, baos.toByteArray()); 298 299 if (sfv.needSignatureFileBytes()) { 300 // see if we have already parsed an external .SF file 301 byte[] bytes = sigFileData.get(key); 302 303 if (bytes == null) { 304 // put this block on queue for later processing 305 // since we don't have the .SF bytes yet 306 // (uname, block); 307 if (debug != null) { 308 debug.println("adding pending block"); 309 } 310 pendingBlocks.add(sfv); 311 return; 312 } else { 313 sfv.setSignatureFile(bytes); 314 } 315 } 316 sfv.process(sigFileSigners, manifestDigests); 317 318 } catch (IOException | CertificateException | 319 NoSuchAlgorithmException | SignatureException e) { 320 if (debug != null) debug.println("processEntry caught: "+e); 321 // ignore and treat as unsigned 322 } 323 } 324 } 325 326 /** 327 * Return an array of java.security.cert.Certificate objects for 328 * the given file in the jar. 329 * @deprecated 330 */ 331 @Deprecated 332 public java.security.cert.Certificate[] getCerts(String name) 333 { 334 return mapSignersToCertArray(getCodeSigners(name)); 335 } 336 337 public java.security.cert.Certificate[] getCerts(JarFile jar, JarEntry entry) 338 { 339 return mapSignersToCertArray(getCodeSigners(jar, entry)); 340 } 341 342 /** 343 * return an array of CodeSigner objects for 344 * the given file in the jar. this array is not cloned. 345 * 346 */ 347 public CodeSigner[] getCodeSigners(String name) 348 { 349 return verifiedSigners.get(name); 350 } 351 352 public CodeSigner[] getCodeSigners(JarFile jar, JarEntry entry) 353 { 354 String name = entry.getName(); 355 if (eagerValidation && sigFileSigners.get(name) != null) { 356 /* 357 * Force a read of the entry data to generate the 358 * verification hash. 359 */ 360 try { 361 InputStream s = jar.getInputStream(entry); 362 byte[] buffer = new byte[1024]; 363 int n = buffer.length; 364 while (n != -1) { 365 n = s.read(buffer, 0, buffer.length); 366 } 367 s.close(); 368 } catch (IOException e) { 369 } 370 } 371 return getCodeSigners(name); 372 } 373 374 /* 375 * Convert an array of signers into an array of concatenated certificate 376 * arrays. 377 */ 378 private static java.security.cert.Certificate[] mapSignersToCertArray( 379 CodeSigner[] signers) { 380 381 if (signers != null) { 382 ArrayList<java.security.cert.Certificate> certChains = new ArrayList<>(); 383 for (CodeSigner signer : signers) { 384 certChains.addAll( 385 signer.getSignerCertPath().getCertificates()); 386 } 387 388 // Convert into a Certificate[] 389 return certChains.toArray( 390 new java.security.cert.Certificate[certChains.size()]); 391 } 392 return null; 393 } 394 395 /** 396 * returns true if there no files to verify. 397 * should only be called after all the META-INF entries 398 * have been processed. 399 */ 400 boolean nothingToVerify() 401 { 402 return (anyToVerify == false); 403 } 404 405 /** 406 * called to let us know we have processed all the 407 * META-INF entries, and if we re-read one of them, don't 408 * re-process it. Also gets rid of any data structures 409 * we needed when parsing META-INF entries. 410 */ 411 void doneWithMeta() 412 { 413 parsingMeta = false; 414 anyToVerify = !sigFileSigners.isEmpty(); 415 baos = null; 416 sigFileData = null; 417 pendingBlocks = null; 418 signerCache = null; 419 manDig = null; 420 // MANIFEST.MF is always treated as signed and verified, 421 // move its signers from sigFileSigners to verifiedSigners. 422 if (sigFileSigners.containsKey(JarFile.MANIFEST_NAME)) { 423 CodeSigner[] codeSigners = sigFileSigners.remove(JarFile.MANIFEST_NAME); 424 verifiedSigners.put(JarFile.MANIFEST_NAME, codeSigners); 425 } 426 } 427 428 static class VerifierStream extends java.io.InputStream { 429 430 private InputStream is; 431 private JarVerifier jv; 432 private ManifestEntryVerifier mev; 433 private long numLeft; 434 435 VerifierStream(Manifest man, 436 JarEntry je, 437 InputStream is, 438 JarVerifier jv) throws IOException 439 { 440 this.is = Objects.requireNonNull(is); 441 this.jv = jv; 442 this.mev = new ManifestEntryVerifier(man); 443 this.jv.beginEntry(je, mev); 444 this.numLeft = je.getSize(); 445 if (this.numLeft == 0) 446 this.jv.update(-1, this.mev); 447 } 448 449 public int read() throws IOException 450 { 451 ensureOpen(); 452 if (numLeft > 0) { 453 int b = is.read(); 454 jv.update(b, mev); 455 numLeft--; 456 if (numLeft == 0) 457 jv.update(-1, mev); 458 return b; 459 } else { 460 return -1; 461 } 462 } 463 464 public int read(byte b[], int off, int len) throws IOException { 465 ensureOpen(); 466 if ((numLeft > 0) && (numLeft < len)) { 467 len = (int)numLeft; 468 } 469 470 if (numLeft > 0) { 471 int n = is.read(b, off, len); 472 jv.update(n, b, off, len, mev); 473 numLeft -= n; 474 if (numLeft == 0) 475 jv.update(-1, b, off, len, mev); 476 return n; 477 } else { 478 return -1; 479 } 480 } 481 482 public void close() 483 throws IOException 484 { 485 if (is != null) 486 is.close(); 487 is = null; 488 mev = null; 489 jv = null; 490 } 491 492 public int available() throws IOException { 493 ensureOpen(); 494 return is.available(); 495 } 496 497 private void ensureOpen() throws IOException { 498 if (is == null) { 499 throw new IOException("stream closed"); 500 } 501 } 502 } 503 504 // Extended JavaUtilJarAccess CodeSource API Support 505 506 private Map<URL, Map<CodeSigner[], CodeSource>> urlToCodeSourceMap = new HashMap<>(); 507 private Map<CodeSigner[], CodeSource> signerToCodeSource = new HashMap<>(); 508 private URL lastURL; 509 private Map<CodeSigner[], CodeSource> lastURLMap; 510 511 /* 512 * Create a unique mapping from codeSigner cache entries to CodeSource. 513 * In theory, multiple URLs origins could map to a single locally cached 514 * and shared JAR file although in practice there will be a single URL in use. 515 */ 516 private synchronized CodeSource mapSignersToCodeSource(URL url, CodeSigner[] signers) { 517 Map<CodeSigner[], CodeSource> map; 518 if (url == lastURL) { 519 map = lastURLMap; 520 } else { 521 map = urlToCodeSourceMap.get(url); 522 if (map == null) { 523 map = new HashMap<>(); 524 urlToCodeSourceMap.put(url, map); 525 } 526 lastURLMap = map; 527 lastURL = url; 528 } 529 CodeSource cs = map.get(signers); 530 if (cs == null) { 531 cs = new VerifierCodeSource(csdomain, url, signers); 532 signerToCodeSource.put(signers, cs); 533 } 534 return cs; 535 } 536 537 private CodeSource[] mapSignersToCodeSources(URL url, List<CodeSigner[]> signers, boolean unsigned) { 538 List<CodeSource> sources = new ArrayList<>(); 539 540 for (CodeSigner[] signer : signers) { 541 sources.add(mapSignersToCodeSource(url, signer)); 542 } 543 if (unsigned) { 544 sources.add(mapSignersToCodeSource(url, null)); 545 } 546 return sources.toArray(new CodeSource[sources.size()]); 547 } 548 private CodeSigner[] emptySigner = new CodeSigner[0]; 549 550 /* 551 * Match CodeSource to a CodeSigner[] in the signer cache. 552 */ 553 private CodeSigner[] findMatchingSigners(CodeSource cs) { 554 if (cs instanceof VerifierCodeSource) { 555 VerifierCodeSource vcs = (VerifierCodeSource) cs; 556 if (vcs.isSameDomain(csdomain)) { 557 return ((VerifierCodeSource) cs).getPrivateSigners(); 558 } 559 } 560 561 /* 562 * In practice signers should always be optimized above 563 * but this handles a CodeSource of any type, just in case. 564 */ 565 CodeSource[] sources = mapSignersToCodeSources(cs.getLocation(), getJarCodeSigners(), true); 566 List<CodeSource> sourceList = new ArrayList<>(); 567 for (CodeSource source : sources) { 568 sourceList.add(source); 569 } 570 int j = sourceList.indexOf(cs); 571 if (j != -1) { 572 CodeSigner[] match; 573 match = ((VerifierCodeSource) sourceList.get(j)).getPrivateSigners(); 574 if (match == null) { 575 match = emptySigner; 576 } 577 return match; 578 } 579 return null; 580 } 581 582 /* 583 * Instances of this class hold uncopied references to internal 584 * signing data that can be compared by object reference identity. 585 */ 586 private static class VerifierCodeSource extends CodeSource { 587 @java.io.Serial 588 private static final long serialVersionUID = -9047366145967768825L; 589 590 URL vlocation; 591 CodeSigner[] vsigners; 592 java.security.cert.Certificate[] vcerts; 593 @SuppressWarnings("serial") // Not statically typed as Serializable 594 Object csdomain; 595 596 VerifierCodeSource(Object csdomain, URL location, CodeSigner[] signers) { 597 super(location, signers); 598 this.csdomain = csdomain; 599 vlocation = location; 600 vsigners = signers; // from signerCache 601 } 602 603 VerifierCodeSource(Object csdomain, URL location, java.security.cert.Certificate[] certs) { 604 super(location, certs); 605 this.csdomain = csdomain; 606 vlocation = location; 607 vcerts = certs; // from signerCache 608 } 609 610 /* 611 * All VerifierCodeSource instances are constructed based on 612 * singleton signerCache or signerCacheCert entries for each unique signer. 613 * No CodeSigner<->Certificate[] conversion is required. 614 * We use these assumptions to optimize equality comparisons. 615 */ 616 public boolean equals(Object obj) { 617 if (obj == this) { 618 return true; 619 } 620 if (obj instanceof VerifierCodeSource) { 621 VerifierCodeSource that = (VerifierCodeSource) obj; 622 623 /* 624 * Only compare against other per-signer singletons constructed 625 * on behalf of the same JarFile instance. Otherwise, compare 626 * things the slower way. 627 */ 628 if (isSameDomain(that.csdomain)) { 629 if (that.vsigners != this.vsigners 630 || that.vcerts != this.vcerts) { 631 return false; 632 } 633 if (that.vlocation != null) { 634 return that.vlocation.equals(this.vlocation); 635 } else if (this.vlocation != null) { 636 return this.vlocation.equals(that.vlocation); 637 } else { // both null 638 return true; 639 } 640 } 641 } 642 return super.equals(obj); 643 } 644 645 boolean isSameDomain(Object csdomain) { 646 return this.csdomain == csdomain; 647 } 648 649 private CodeSigner[] getPrivateSigners() { 650 return vsigners; 651 } 652 653 private java.security.cert.Certificate[] getPrivateCertificates() { 654 return vcerts; 655 } 656 } 657 private Map<String, CodeSigner[]> signerMap; 658 659 private synchronized Map<String, CodeSigner[]> signerMap() { 660 if (signerMap == null) { 661 /* 662 * Snapshot signer state so it doesn't change on us. We care 663 * only about the asserted signatures. Verification of 664 * signature validity happens via the JarEntry apis. 665 */ 666 signerMap = new HashMap<>(verifiedSigners.size() + sigFileSigners.size()); 667 signerMap.putAll(verifiedSigners); 668 signerMap.putAll(sigFileSigners); 669 } 670 return signerMap; 671 } 672 673 public synchronized Enumeration<String> entryNames(JarFile jar, final CodeSource[] cs) { 674 final Map<String, CodeSigner[]> map = signerMap(); 675 final Iterator<Map.Entry<String, CodeSigner[]>> itor = map.entrySet().iterator(); 676 boolean matchUnsigned = false; 677 678 /* 679 * Grab a single copy of the CodeSigner arrays. Check 680 * to see if we can optimize CodeSigner equality test. 681 */ 682 List<CodeSigner[]> req = new ArrayList<>(cs.length); 683 for (CodeSource c : cs) { 684 CodeSigner[] match = findMatchingSigners(c); 685 if (match != null) { 686 if (match.length > 0) { 687 req.add(match); 688 } else { 689 matchUnsigned = true; 690 } 691 } else { 692 matchUnsigned = true; 693 } 694 } 695 696 final List<CodeSigner[]> signersReq = req; 697 final Enumeration<String> enum2 = matchUnsigned ? unsignedEntryNames(jar) : Collections.emptyEnumeration(); 698 699 return new Enumeration<>() { 700 701 String name; 702 703 public boolean hasMoreElements() { 704 if (name != null) { 705 return true; 706 } 707 708 while (itor.hasNext()) { 709 Map.Entry<String, CodeSigner[]> e = itor.next(); 710 if (signersReq.contains(e.getValue())) { 711 name = e.getKey(); 712 return true; 713 } 714 } 715 while (enum2.hasMoreElements()) { 716 name = enum2.nextElement(); 717 return true; 718 } 719 return false; 720 } 721 722 public String nextElement() { 723 if (hasMoreElements()) { 724 String value = name; 725 name = null; 726 return value; 727 } 728 throw new NoSuchElementException(); 729 } 730 }; 731 } 732 733 /* 734 * Like entries() but screens out internal JAR mechanism entries 735 * and includes signed entries with no ZIP data. 736 */ 737 public Enumeration<JarEntry> entries2(final JarFile jar, Enumeration<JarEntry> e) { 738 final Map<String, CodeSigner[]> map = new HashMap<>(); 739 map.putAll(signerMap()); 740 final Enumeration<JarEntry> enum_ = e; 741 return new Enumeration<>() { 742 743 Enumeration<String> signers = null; 744 JarEntry entry; 745 746 public boolean hasMoreElements() { 747 if (entry != null) { 748 return true; 749 } 750 while (enum_.hasMoreElements()) { 751 JarEntry je = enum_.nextElement(); 752 if (JarVerifier.isSigningRelated(je.getName())) { 753 continue; 754 } 755 entry = jar.newEntry(je); 756 return true; 757 } 758 if (signers == null) { 759 signers = Collections.enumeration(map.keySet()); 760 } 761 while (signers.hasMoreElements()) { 762 String name = signers.nextElement(); 763 entry = jar.newEntry(name); 764 return true; 765 } 766 767 // Any map entries left? 768 return false; 769 } 770 771 public JarEntry nextElement() { 772 if (hasMoreElements()) { 773 JarEntry je = entry; 774 map.remove(je.getName()); 775 entry = null; 776 return je; 777 } 778 throw new NoSuchElementException(); 779 } 780 }; 781 } 782 783 // true if file is part of the signature mechanism itself 784 static boolean isSigningRelated(String name) { 785 return SignatureFileVerifier.isSigningRelated(name); 786 } 787 788 private Enumeration<String> unsignedEntryNames(JarFile jar) { 789 final Map<String, CodeSigner[]> map = signerMap(); 790 final Enumeration<JarEntry> entries = jar.entries(); 791 return new Enumeration<>() { 792 793 String name; 794 795 /* 796 * Grab entries from ZIP directory but screen out 797 * metadata. 798 */ 799 public boolean hasMoreElements() { 800 if (name != null) { 801 return true; 802 } 803 while (entries.hasMoreElements()) { 804 String value; 805 ZipEntry e = entries.nextElement(); 806 value = e.getName(); 807 if (e.isDirectory() || isSigningRelated(value)) { 808 continue; 809 } 810 if (map.get(value) == null) { 811 name = value; 812 return true; 813 } 814 } 815 return false; 816 } 817 818 public String nextElement() { 819 if (hasMoreElements()) { 820 String value = name; 821 name = null; 822 return value; 823 } 824 throw new NoSuchElementException(); 825 } 826 }; 827 } 828 private List<CodeSigner[]> jarCodeSigners; 829 830 private synchronized List<CodeSigner[]> getJarCodeSigners() { 831 CodeSigner[] signers; 832 if (jarCodeSigners == null) { 833 HashSet<CodeSigner[]> set = new HashSet<>(); 834 set.addAll(signerMap().values()); 835 jarCodeSigners = new ArrayList<>(); 836 jarCodeSigners.addAll(set); 837 } 838 return jarCodeSigners; 839 } 840 841 public synchronized CodeSource[] getCodeSources(JarFile jar, URL url) { 842 boolean hasUnsigned = unsignedEntryNames(jar).hasMoreElements(); 843 844 return mapSignersToCodeSources(url, getJarCodeSigners(), hasUnsigned); 845 } 846 847 public CodeSource getCodeSource(URL url, String name) { 848 CodeSigner[] signers; 849 850 signers = signerMap().get(name); 851 return mapSignersToCodeSource(url, signers); 852 } 853 854 public CodeSource getCodeSource(URL url, JarFile jar, JarEntry je) { 855 CodeSigner[] signers; 856 857 return mapSignersToCodeSource(url, getCodeSigners(jar, je)); 858 } 859 860 public void setEagerValidation(boolean eager) { 861 eagerValidation = eager; 862 } 863 864 public synchronized List<Object> getManifestDigests() { 865 return Collections.unmodifiableList(manifestDigests); 866 } 867 868 static CodeSource getUnsignedCS(URL url) { 869 return new VerifierCodeSource(null, url, (java.security.cert.Certificate[]) null); 870 } 871 872 /** 873 * Returns whether the name is trusted. Used by 874 * {@link Manifest#getTrustedAttributes(String)}. 875 */ 876 boolean isTrustedManifestEntry(String name) { 877 // How many signers? MANIFEST.MF is always verified 878 CodeSigner[] forMan = verifiedSigners.get(JarFile.MANIFEST_NAME); 879 if (forMan == null) { 880 return true; 881 } 882 // Check sigFileSigners first, because we are mainly dealing with 883 // non-file entries which will stay in sigFileSigners forever. 884 CodeSigner[] forName = sigFileSigners.get(name); 885 if (forName == null) { 886 forName = verifiedSigners.get(name); 887 } 888 // Returns trusted if all signers sign the entry 889 return forName != null && forName.length == forMan.length; 890 } 891 }