46 /* Are we debugging ? */ |
46 /* Are we debugging ? */ |
47 static final Debug debug = Debug.getInstance("jar"); |
47 static final Debug debug = Debug.getInstance("jar"); |
48 |
48 |
49 /* a table mapping names to code signers, for jar entries that have |
49 /* a table mapping names to code signers, for jar entries that have |
50 had their actual hashes verified */ |
50 had their actual hashes verified */ |
51 private Hashtable verifiedSigners; |
51 private Hashtable<String, CodeSigner[]> verifiedSigners; |
52 |
52 |
53 /* a table mapping names to code signers, for jar entries that have |
53 /* a table mapping names to code signers, for jar entries that have |
54 passed the .SF/.DSA/.EC -> MANIFEST check */ |
54 passed the .SF/.DSA/.EC -> MANIFEST check */ |
55 private Hashtable sigFileSigners; |
55 private Hashtable<String, CodeSigner[]> sigFileSigners; |
56 |
56 |
57 /* a hash table to hold .SF bytes */ |
57 /* a hash table to hold .SF bytes */ |
58 private Hashtable sigFileData; |
58 private Hashtable<String, byte[]> sigFileData; |
59 |
59 |
60 /** "queue" of pending PKCS7 blocks that we couldn't parse |
60 /** "queue" of pending PKCS7 blocks that we couldn't parse |
61 * until we parsed the .SF file */ |
61 * until we parsed the .SF file */ |
62 private ArrayList pendingBlocks; |
62 private ArrayList<SignatureFileVerifier> pendingBlocks; |
63 |
63 |
64 /* cache of CodeSigner objects */ |
64 /* cache of CodeSigner objects */ |
65 private ArrayList signerCache; |
65 private ArrayList<CodeSigner[]> signerCache; |
66 |
66 |
67 /* Are we parsing a block? */ |
67 /* Are we parsing a block? */ |
68 private boolean parsingBlockOrSF = false; |
68 private boolean parsingBlockOrSF = false; |
69 |
69 |
70 /* Are we done parsing META-INF entries? */ |
70 /* Are we done parsing META-INF entries? */ |
92 /** collect -DIGEST-MANIFEST values for blacklist */ |
92 /** collect -DIGEST-MANIFEST values for blacklist */ |
93 private List<Object> manifestDigests; |
93 private List<Object> manifestDigests; |
94 |
94 |
95 public JarVerifier(byte rawBytes[]) { |
95 public JarVerifier(byte rawBytes[]) { |
96 manifestRawBytes = rawBytes; |
96 manifestRawBytes = rawBytes; |
97 sigFileSigners = new Hashtable(); |
97 sigFileSigners = new Hashtable<>(); |
98 verifiedSigners = new Hashtable(); |
98 verifiedSigners = new Hashtable<>(); |
99 sigFileData = new Hashtable(11); |
99 sigFileData = new Hashtable<>(11); |
100 pendingBlocks = new ArrayList(); |
100 pendingBlocks = new ArrayList<>(); |
101 baos = new ByteArrayOutputStream(); |
101 baos = new ByteArrayOutputStream(); |
102 manifestDigests = new ArrayList<>(); |
102 manifestDigests = new ArrayList<>(); |
103 } |
103 } |
104 |
104 |
105 /** |
105 /** |
246 byte bytes[] = baos.toByteArray(); |
246 byte bytes[] = baos.toByteArray(); |
247 // add to sigFileData in case future blocks need it |
247 // add to sigFileData in case future blocks need it |
248 sigFileData.put(key, bytes); |
248 sigFileData.put(key, bytes); |
249 // check pending blocks, we can now process |
249 // check pending blocks, we can now process |
250 // anyone waiting for this .SF file |
250 // anyone waiting for this .SF file |
251 Iterator it = pendingBlocks.iterator(); |
251 Iterator<SignatureFileVerifier> it = pendingBlocks.iterator(); |
252 while (it.hasNext()) { |
252 while (it.hasNext()) { |
253 SignatureFileVerifier sfv = |
253 SignatureFileVerifier sfv = it.next(); |
254 (SignatureFileVerifier) it.next(); |
|
255 if (sfv.needSignatureFile(key)) { |
254 if (sfv.needSignatureFile(key)) { |
256 if (debug != null) { |
255 if (debug != null) { |
257 debug.println( |
256 debug.println( |
258 "processEntry: processing pending block"); |
257 "processEntry: processing pending block"); |
259 } |
258 } |
268 // now we are parsing a signature block file |
267 // now we are parsing a signature block file |
269 |
268 |
270 String key = uname.substring(0, uname.lastIndexOf(".")); |
269 String key = uname.substring(0, uname.lastIndexOf(".")); |
271 |
270 |
272 if (signerCache == null) |
271 if (signerCache == null) |
273 signerCache = new ArrayList(); |
272 signerCache = new ArrayList<>(); |
274 |
273 |
275 if (manDig == null) { |
274 if (manDig == null) { |
276 synchronized(manifestRawBytes) { |
275 synchronized(manifestRawBytes) { |
277 if (manDig == null) { |
276 if (manDig == null) { |
278 manDig = new ManifestDigester(manifestRawBytes); |
277 manDig = new ManifestDigester(manifestRawBytes); |
285 new SignatureFileVerifier(signerCache, |
284 new SignatureFileVerifier(signerCache, |
286 manDig, uname, baos.toByteArray()); |
285 manDig, uname, baos.toByteArray()); |
287 |
286 |
288 if (sfv.needSignatureFileBytes()) { |
287 if (sfv.needSignatureFileBytes()) { |
289 // see if we have already parsed an external .SF file |
288 // see if we have already parsed an external .SF file |
290 byte[] bytes = (byte[]) sigFileData.get(key); |
289 byte[] bytes = sigFileData.get(key); |
291 |
290 |
292 if (bytes == null) { |
291 if (bytes == null) { |
293 // put this block on queue for later processing |
292 // put this block on queue for later processing |
294 // since we don't have the .SF bytes yet |
293 // since we don't have the .SF bytes yet |
295 // (uname, block); |
294 // (uname, block); |
374 */ |
373 */ |
375 private static java.security.cert.Certificate[] mapSignersToCertArray( |
374 private static java.security.cert.Certificate[] mapSignersToCertArray( |
376 CodeSigner[] signers) { |
375 CodeSigner[] signers) { |
377 |
376 |
378 if (signers != null) { |
377 if (signers != null) { |
379 ArrayList certChains = new ArrayList(); |
378 ArrayList<java.security.cert.Certificate> certChains = new ArrayList<>(); |
380 for (int i = 0; i < signers.length; i++) { |
379 for (int i = 0; i < signers.length; i++) { |
381 certChains.addAll( |
380 certChains.addAll( |
382 signers[i].getSignerCertPath().getCertificates()); |
381 signers[i].getSignerCertPath().getCertificates()); |
383 } |
382 } |
384 |
383 |
385 // Convert into a Certificate[] |
384 // Convert into a Certificate[] |
386 return (java.security.cert.Certificate[]) |
385 return certChains.toArray( |
387 certChains.toArray( |
|
388 new java.security.cert.Certificate[certChains.size()]); |
386 new java.security.cert.Certificate[certChains.size()]); |
389 } |
387 } |
390 return null; |
388 return null; |
391 } |
389 } |
392 |
390 |
416 signerCache = null; |
414 signerCache = null; |
417 manDig = null; |
415 manDig = null; |
418 // MANIFEST.MF is always treated as signed and verified, |
416 // MANIFEST.MF is always treated as signed and verified, |
419 // move its signers from sigFileSigners to verifiedSigners. |
417 // move its signers from sigFileSigners to verifiedSigners. |
420 if (sigFileSigners.containsKey(JarFile.MANIFEST_NAME)) { |
418 if (sigFileSigners.containsKey(JarFile.MANIFEST_NAME)) { |
421 verifiedSigners.put(JarFile.MANIFEST_NAME, |
419 CodeSigner[] codeSigners = sigFileSigners.remove(JarFile.MANIFEST_NAME); |
422 sigFileSigners.remove(JarFile.MANIFEST_NAME)); |
420 verifiedSigners.put(JarFile.MANIFEST_NAME, codeSigners); |
423 } |
421 } |
424 } |
422 } |
425 |
423 |
426 static class VerifierStream extends java.io.InputStream { |
424 static class VerifierStream extends java.io.InputStream { |
427 |
425 |
491 |
489 |
492 } |
490 } |
493 |
491 |
494 // Extended JavaUtilJarAccess CodeSource API Support |
492 // Extended JavaUtilJarAccess CodeSource API Support |
495 |
493 |
496 private Map urlToCodeSourceMap = new HashMap(); |
494 private Map<URL, Map<CodeSigner[], CodeSource>> urlToCodeSourceMap = new HashMap<>(); |
497 private Map signerToCodeSource = new HashMap(); |
495 private Map<CodeSigner[], CodeSource> signerToCodeSource = new HashMap<>(); |
498 private URL lastURL; |
496 private URL lastURL; |
499 private Map lastURLMap; |
497 private Map<CodeSigner[], CodeSource> lastURLMap; |
500 |
498 |
501 /* |
499 /* |
502 * Create a unique mapping from codeSigner cache entries to CodeSource. |
500 * Create a unique mapping from codeSigner cache entries to CodeSource. |
503 * In theory, multiple URLs origins could map to a single locally cached |
501 * In theory, multiple URLs origins could map to a single locally cached |
504 * and shared JAR file although in practice there will be a single URL in use. |
502 * and shared JAR file although in practice there will be a single URL in use. |
505 */ |
503 */ |
506 private synchronized CodeSource mapSignersToCodeSource(URL url, CodeSigner[] signers) { |
504 private synchronized CodeSource mapSignersToCodeSource(URL url, CodeSigner[] signers) { |
507 Map map; |
505 Map<CodeSigner[], CodeSource> map; |
508 if (url == lastURL) { |
506 if (url == lastURL) { |
509 map = lastURLMap; |
507 map = lastURLMap; |
510 } else { |
508 } else { |
511 map = (Map) urlToCodeSourceMap.get(url); |
509 map = urlToCodeSourceMap.get(url); |
512 if (map == null) { |
510 if (map == null) { |
513 map = new HashMap(); |
511 map = new HashMap<>(); |
514 urlToCodeSourceMap.put(url, map); |
512 urlToCodeSourceMap.put(url, map); |
515 } |
513 } |
516 lastURLMap = map; |
514 lastURLMap = map; |
517 lastURL = url; |
515 lastURL = url; |
518 } |
516 } |
519 CodeSource cs = (CodeSource) map.get(signers); |
517 CodeSource cs = map.get(signers); |
520 if (cs == null) { |
518 if (cs == null) { |
521 cs = new VerifierCodeSource(csdomain, url, signers); |
519 cs = new VerifierCodeSource(csdomain, url, signers); |
522 signerToCodeSource.put(signers, cs); |
520 signerToCodeSource.put(signers, cs); |
523 } |
521 } |
524 return cs; |
522 return cs; |
525 } |
523 } |
526 |
524 |
527 private CodeSource[] mapSignersToCodeSources(URL url, List signers, boolean unsigned) { |
525 private CodeSource[] mapSignersToCodeSources(URL url, List<CodeSigner[]> signers, boolean unsigned) { |
528 List sources = new ArrayList(); |
526 List<CodeSource> sources = new ArrayList<>(); |
529 |
527 |
530 for (int i = 0; i < signers.size(); i++) { |
528 for (int i = 0; i < signers.size(); i++) { |
531 sources.add(mapSignersToCodeSource(url, (CodeSigner[]) signers.get(i))); |
529 sources.add(mapSignersToCodeSource(url, signers.get(i))); |
532 } |
530 } |
533 if (unsigned) { |
531 if (unsigned) { |
534 sources.add(mapSignersToCodeSource(url, null)); |
532 sources.add(mapSignersToCodeSource(url, null)); |
535 } |
533 } |
536 return (CodeSource[]) sources.toArray(new CodeSource[sources.size()]); |
534 return sources.toArray(new CodeSource[sources.size()]); |
537 } |
535 } |
538 private CodeSigner[] emptySigner = new CodeSigner[0]; |
536 private CodeSigner[] emptySigner = new CodeSigner[0]; |
539 |
537 |
540 /* |
538 /* |
541 * Match CodeSource to a CodeSigner[] in the signer cache. |
539 * Match CodeSource to a CodeSigner[] in the signer cache. |
551 /* |
549 /* |
552 * In practice signers should always be optimized above |
550 * In practice signers should always be optimized above |
553 * but this handles a CodeSource of any type, just in case. |
551 * but this handles a CodeSource of any type, just in case. |
554 */ |
552 */ |
555 CodeSource[] sources = mapSignersToCodeSources(cs.getLocation(), getJarCodeSigners(), true); |
553 CodeSource[] sources = mapSignersToCodeSources(cs.getLocation(), getJarCodeSigners(), true); |
556 List sourceList = new ArrayList(); |
554 List<CodeSource> sourceList = new ArrayList<>(); |
557 for (int i = 0; i < sources.length; i++) { |
555 for (int i = 0; i < sources.length; i++) { |
558 sourceList.add(sources[i]); |
556 sourceList.add(sources[i]); |
559 } |
557 } |
560 int j = sourceList.indexOf(cs); |
558 int j = sourceList.indexOf(cs); |
561 if (j != -1) { |
559 if (j != -1) { |
639 |
638 |
640 private java.security.cert.Certificate[] getPrivateCertificates() { |
639 private java.security.cert.Certificate[] getPrivateCertificates() { |
641 return vcerts; |
640 return vcerts; |
642 } |
641 } |
643 } |
642 } |
644 private Map signerMap; |
643 private Map<String, CodeSigner[]> signerMap; |
645 |
644 |
646 private synchronized Map signerMap() { |
645 private synchronized Map<String, CodeSigner[]> signerMap() { |
647 if (signerMap == null) { |
646 if (signerMap == null) { |
648 /* |
647 /* |
649 * Snapshot signer state so it doesn't change on us. We care |
648 * Snapshot signer state so it doesn't change on us. We care |
650 * only about the asserted signatures. Verification of |
649 * only about the asserted signatures. Verification of |
651 * signature validity happens via the JarEntry apis. |
650 * signature validity happens via the JarEntry apis. |
652 */ |
651 */ |
653 signerMap = new HashMap(verifiedSigners.size() + sigFileSigners.size()); |
652 signerMap = new HashMap<>(verifiedSigners.size() + sigFileSigners.size()); |
654 signerMap.putAll(verifiedSigners); |
653 signerMap.putAll(verifiedSigners); |
655 signerMap.putAll(sigFileSigners); |
654 signerMap.putAll(sigFileSigners); |
656 } |
655 } |
657 return signerMap; |
656 return signerMap; |
658 } |
657 } |
659 |
658 |
660 public synchronized Enumeration<String> entryNames(JarFile jar, final CodeSource[] cs) { |
659 public synchronized Enumeration<String> entryNames(JarFile jar, final CodeSource[] cs) { |
661 final Map map = signerMap(); |
660 final Map<String, CodeSigner[]> map = signerMap(); |
662 final Iterator itor = map.entrySet().iterator(); |
661 final Iterator<Map.Entry<String, CodeSigner[]>> itor = map.entrySet().iterator(); |
663 boolean matchUnsigned = false; |
662 boolean matchUnsigned = false; |
664 |
663 |
665 /* |
664 /* |
666 * Grab a single copy of the CodeSigner arrays. Check |
665 * Grab a single copy of the CodeSigner arrays. Check |
667 * to see if we can optimize CodeSigner equality test. |
666 * to see if we can optimize CodeSigner equality test. |
668 */ |
667 */ |
669 List req = new ArrayList(cs.length); |
668 List<CodeSigner[]> req = new ArrayList<>(cs.length); |
670 for (int i = 0; i < cs.length; i++) { |
669 for (int i = 0; i < cs.length; i++) { |
671 CodeSigner[] match = findMatchingSigners(cs[i]); |
670 CodeSigner[] match = findMatchingSigners(cs[i]); |
672 if (match != null) { |
671 if (match != null) { |
673 if (match.length > 0) { |
672 if (match.length > 0) { |
674 req.add(match); |
673 req.add(match); |
717 |
716 |
718 /* |
717 /* |
719 * Like entries() but screens out internal JAR mechanism entries |
718 * Like entries() but screens out internal JAR mechanism entries |
720 * and includes signed entries with no ZIP data. |
719 * and includes signed entries with no ZIP data. |
721 */ |
720 */ |
722 public Enumeration<JarEntry> entries2(final JarFile jar, Enumeration e) { |
721 public Enumeration<JarEntry> entries2(final JarFile jar, Enumeration<? extends ZipEntry> e) { |
723 final Map map = new HashMap(); |
722 final Map<String, CodeSigner[]> map = new HashMap<>(); |
724 map.putAll(signerMap()); |
723 map.putAll(signerMap()); |
725 final Enumeration enum_ = e; |
724 final Enumeration<? extends ZipEntry> enum_ = e; |
726 return new Enumeration<JarEntry>() { |
725 return new Enumeration<JarEntry>() { |
727 |
726 |
728 Enumeration signers = null; |
727 Enumeration<String> signers = null; |
729 JarEntry entry; |
728 JarEntry entry; |
730 |
729 |
731 public boolean hasMoreElements() { |
730 public boolean hasMoreElements() { |
732 if (entry != null) { |
731 if (entry != null) { |
733 return true; |
732 return true; |
734 } |
733 } |
735 while (enum_.hasMoreElements()) { |
734 while (enum_.hasMoreElements()) { |
736 ZipEntry ze = (ZipEntry) enum_.nextElement(); |
735 ZipEntry ze = enum_.nextElement(); |
737 if (JarVerifier.isSigningRelated(ze.getName())) { |
736 if (JarVerifier.isSigningRelated(ze.getName())) { |
738 continue; |
737 continue; |
739 } |
738 } |
740 entry = jar.newEntry(ze); |
739 entry = jar.newEntry(ze); |
741 return true; |
740 return true; |
742 } |
741 } |
743 if (signers == null) { |
742 if (signers == null) { |
744 signers = Collections.enumeration(map.keySet()); |
743 signers = Collections.enumeration(map.keySet()); |
745 } |
744 } |
746 while (signers.hasMoreElements()) { |
745 while (signers.hasMoreElements()) { |
747 String name = (String) signers.nextElement(); |
746 String name = signers.nextElement(); |
748 entry = jar.newEntry(new ZipEntry(name)); |
747 entry = jar.newEntry(new ZipEntry(name)); |
749 return true; |
748 return true; |
750 } |
749 } |
751 |
750 |
752 // Any map entries left? |
751 // Any map entries left? |
834 } |
833 } |
835 throw new NoSuchElementException(); |
834 throw new NoSuchElementException(); |
836 } |
835 } |
837 }; |
836 }; |
838 } |
837 } |
839 private List jarCodeSigners; |
838 private List<CodeSigner[]> jarCodeSigners; |
840 |
839 |
841 private synchronized List getJarCodeSigners() { |
840 private synchronized List<CodeSigner[]> getJarCodeSigners() { |
842 CodeSigner[] signers; |
841 CodeSigner[] signers; |
843 if (jarCodeSigners == null) { |
842 if (jarCodeSigners == null) { |
844 HashSet set = new HashSet(); |
843 HashSet<CodeSigner[]> set = new HashSet<>(); |
845 set.addAll(signerMap().values()); |
844 set.addAll(signerMap().values()); |
846 jarCodeSigners = new ArrayList(); |
845 jarCodeSigners = new ArrayList<>(); |
847 jarCodeSigners.addAll(set); |
846 jarCodeSigners.addAll(set); |
848 } |
847 } |
849 return jarCodeSigners; |
848 return jarCodeSigners; |
850 } |
849 } |
851 |
850 |
856 } |
855 } |
857 |
856 |
858 public CodeSource getCodeSource(URL url, String name) { |
857 public CodeSource getCodeSource(URL url, String name) { |
859 CodeSigner[] signers; |
858 CodeSigner[] signers; |
860 |
859 |
861 signers = (CodeSigner[]) signerMap().get(name); |
860 signers = signerMap().get(name); |
862 return mapSignersToCodeSource(url, signers); |
861 return mapSignersToCodeSource(url, signers); |
863 } |
862 } |
864 |
863 |
865 public CodeSource getCodeSource(URL url, JarFile jar, JarEntry je) { |
864 public CodeSource getCodeSource(URL url, JarFile jar, JarEntry je) { |
866 CodeSigner[] signers; |
865 CodeSigner[] signers; |