diff --git a/make/java/security/Makefile b/make/java/security/Makefile index 95c56767fae007441a511c7b72725cf4dfc0eff5..1d28b60f2ff0dadac2ec6d35f3e2e1ba1070d73b 100644 --- a/make/java/security/Makefile +++ b/make/java/security/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 1996, 2010 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1996, 2011 Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,8 @@ CACERTS_BUILD = $(LIBDIR)/security/cacerts ifndef OPENJDK BLACKLIST_SRC = $(CLOSED_SHARE_SRC)/lib/security/blacklist BLACKLIST_BUILD = $(LIBDIR)/security/blacklist + TRUSTEDLIBS_SRC = $(CLOSED_SHARE_SRC)/lib/security/trusted.libraries + TRUSTEDLIBS_BUILD = $(LIBDIR)/security/trusted.libraries endif FILES_class = $(FILES_java:%.java=$(CLASSBINDIR)/%.class) @@ -77,7 +79,7 @@ include $(BUILDDIR)/common/Rules.gmk ifdef OPENJDK build: properties policy cacerts else -build: properties policy cacerts blacklist +build: properties policy cacerts blacklist trustedlibs endif install: all @@ -90,6 +92,8 @@ cacerts: classes $(CACERTS_BUILD) blacklist: classes $(BLACKLIST_BUILD) +trustedlibs: classes $(TRUSTEDLIBS_BUILD) + $(PROPS_BUILD): $(PROPS_SRC) $(install-file) @@ -102,9 +106,12 @@ $(CACERTS_BUILD): $(CACERTS_SRC) $(BLACKLIST_BUILD): $(BLACKLIST_SRC) $(install-file) +$(TRUSTEDLIBS_BUILD): $(TRUSTEDLIBS_SRC) + $(install-file) + clean clobber:: .delete.classlist $(RM) -r $(CLASSBINDIR)/java/security - $(RM) $(PROPS_BUILD) $(POLICY_BUILD) $(CACERTS_BUILD) $(BLACKLIST_BUILD) + $(RM) $(PROPS_BUILD) $(POLICY_BUILD) $(CACERTS_BUILD) $(BLACKLIST_BUILD) $(TRUSTEDLIBS_BUILD) # Additional Rule for building sun.security.util $(CLASSBINDIR)/%.class: $(SHARE_SRC)/sun/%.java diff --git a/src/share/classes/java/util/jar/JarFile.java b/src/share/classes/java/util/jar/JarFile.java index e42d41fb79992898dd20c6eff9d3b133633f5940..a5795c72763c81e820034b4429548c736028062a 100644 --- a/src/share/classes/java/util/jar/JarFile.java +++ b/src/share/classes/java/util/jar/JarFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,13 @@ package java.util.jar; import java.io.*; import java.lang.ref.SoftReference; +import java.net.URL; import java.util.*; import java.util.zip.*; import java.security.CodeSigner; import java.security.cert.Certificate; import java.security.AccessController; +import java.security.CodeSource; import sun.security.action.GetPropertyAction; import sun.security.util.ManifestEntryVerifier; import sun.misc.SharedSecrets; @@ -262,7 +264,7 @@ class JarFile extends ZipFile { throw new RuntimeException(e); } if (certs == null && jv != null) { - certs = jv.getCerts(getName()); + certs = jv.getCerts(JarFile.this, this); } return certs == null ? null : certs.clone(); } @@ -273,7 +275,7 @@ class JarFile extends ZipFile { throw new RuntimeException(e); } if (signers == null && jv != null) { - signers = jv.getCodeSigners(getName()); + signers = jv.getCodeSigners(JarFile.this, this); } return signers == null ? null : signers.clone(); } @@ -544,4 +546,191 @@ class JarFile extends ZipFile { } return false; } + + private synchronized void ensureInitialization() { + try { + maybeInstantiateVerifier(); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (jv != null && !jvInitialized) { + initializeVerifier(); + jvInitialized = true; + } + } + + JarEntry newEntry(ZipEntry ze) { + return new JarFileEntry(ze); + } + + Enumeration entryNames(CodeSource[] cs) { + ensureInitialization(); + if (jv != null) { + return jv.entryNames(this, cs); + } + + /* + * JAR file has no signed content. Is there a non-signing + * code source? + */ + boolean includeUnsigned = false; + for (int i = 0; i < cs.length; i++) { + if (cs[i].getCodeSigners() == null) { + includeUnsigned = true; + break; + } + } + if (includeUnsigned) { + return unsignedEntryNames(); + } else { + return new Enumeration() { + + public boolean hasMoreElements() { + return false; + } + + public String nextElement() { + throw new NoSuchElementException(); + } + }; + } + } + + /** + * Returns an enumeration of the zip file entries + * excluding internal JAR mechanism entries and including + * signed entries missing from the ZIP directory. + */ + Enumeration entries2() { + ensureInitialization(); + if (jv != null) { + return jv.entries2(this, super.entries()); + } + + // screen out entries which are never signed + final Enumeration enum_ = super.entries(); + return new Enumeration() { + + ZipEntry entry; + + public boolean hasMoreElements() { + if (entry != null) { + return true; + } + while (enum_.hasMoreElements()) { + ZipEntry ze = (ZipEntry) enum_.nextElement(); + if (JarVerifier.isSigningRelated(ze.getName())) { + continue; + } + entry = ze; + return true; + } + return false; + } + + public JarFileEntry nextElement() { + if (hasMoreElements()) { + ZipEntry ze = entry; + entry = null; + return new JarFileEntry(ze); + } + throw new NoSuchElementException(); + } + }; + } + + CodeSource[] getCodeSources(URL url) { + ensureInitialization(); + if (jv != null) { + return jv.getCodeSources(this, url); + } + + /* + * JAR file has no signed content. Is there a non-signing + * code source? + */ + Enumeration unsigned = unsignedEntryNames(); + if (unsigned.hasMoreElements()) { + return new CodeSource[]{JarVerifier.getUnsignedCS(url)}; + } else { + return null; + } + } + + private Enumeration unsignedEntryNames() { + final Enumeration entries = entries(); + return new Enumeration() { + + String name; + + /* + * Grab entries from ZIP directory but screen out + * metadata. + */ + public boolean hasMoreElements() { + if (name != null) { + return true; + } + while (entries.hasMoreElements()) { + String value; + ZipEntry e = (ZipEntry) entries.nextElement(); + value = e.getName(); + if (e.isDirectory() || JarVerifier.isSigningRelated(value)) { + continue; + } + name = value; + return true; + } + return false; + } + + public String nextElement() { + if (hasMoreElements()) { + String value = name; + name = null; + return value; + } + throw new NoSuchElementException(); + } + }; + } + + CodeSource getCodeSource(URL url, String name) { + ensureInitialization(); + if (jv != null) { + if (jv.eagerValidation) { + CodeSource cs = null; + JarEntry je = getJarEntry(name); + if (je != null) { + cs = jv.getCodeSource(url, this, je); + } else { + cs = jv.getCodeSource(url, name); + } + return cs; + } else { + return jv.getCodeSource(url, name); + } + } + + return JarVerifier.getUnsignedCS(url); + } + + void setEagerValidation(boolean eager) { + try { + maybeInstantiateVerifier(); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (jv != null) { + jv.setEagerValidation(eager); + } + } + + List getManifestDigests() { + ensureInitialization(); + if (jv != null) { + return jv.getManifestDigests(); + } + return new ArrayList(); + } } diff --git a/src/share/classes/java/util/jar/JarVerifier.java b/src/share/classes/java/util/jar/JarVerifier.java index 33c67c15a6dcbe84c438daeffdc608c946ffd7eb..abbb85e3768862c8bf9e00a2820260a7fa1d49ca 100644 --- a/src/share/classes/java/util/jar/JarVerifier.java +++ b/src/share/classes/java/util/jar/JarVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,11 @@ package java.util.jar; import java.io.*; +import java.net.URL; import java.util.*; import java.security.*; import java.security.cert.CertificateException; +import java.util.zip.ZipEntry; import sun.security.util.ManifestDigester; import sun.security.util.ManifestEntryVerifier; @@ -81,6 +83,15 @@ class JarVerifier { /** the bytes for the manDig object */ byte manifestRawBytes[] = null; + /** controls eager signature validation */ + boolean eagerValidation; + + /** makes code source singleton instances unique to us */ + private Object csdomain = new Object(); + + /** collect -DIGEST-MANIFEST values for blacklist */ + private List manifestDigests; + public JarVerifier(byte rawBytes[]) { manifestRawBytes = rawBytes; sigFileSigners = new Hashtable(); @@ -88,6 +99,7 @@ class JarVerifier { sigFileData = new Hashtable(11); pendingBlocks = new ArrayList(); baos = new ByteArrayOutputStream(); + manifestDigests = new ArrayList(); } /** @@ -247,7 +259,7 @@ class JarVerifier { } sfv.setSignatureFile(bytes); - sfv.process(sigFileSigners); + sfv.process(sigFileSigners, manifestDigests); } } return; @@ -290,7 +302,7 @@ class JarVerifier { sfv.setSignatureFile(bytes); } } - sfv.process(sigFileSigners); + sfv.process(sigFileSigners, manifestDigests); } catch (IOException ioe) { // e.g. sun.security.pkcs.ParsingException @@ -312,12 +324,18 @@ class JarVerifier { /** * Return an array of java.security.cert.Certificate objects for * the given file in the jar. + * @deprecated */ public java.security.cert.Certificate[] getCerts(String name) { return mapSignersToCertArray(getCodeSigners(name)); } + public java.security.cert.Certificate[] getCerts(JarFile jar, JarEntry entry) + { + return mapSignersToCertArray(getCodeSigners(jar, entry)); + } + /** * return an array of CodeSigner objects for * the given file in the jar. this array is not cloned. @@ -328,6 +346,28 @@ class JarVerifier { return (CodeSigner[])verifiedSigners.get(name); } + public CodeSigner[] getCodeSigners(JarFile jar, JarEntry entry) + { + String name = entry.getName(); + if (eagerValidation && sigFileSigners.get(name) != null) { + /* + * Force a read of the entry data to generate the + * verification hash. + */ + try { + InputStream s = jar.getInputStream(entry); + byte[] buffer = new byte[1024]; + int n = buffer.length; + while (n != -1) { + n = s.read(buffer, 0, buffer.length); + } + s.close(); + } catch (IOException e) { + } + } + return getCodeSigners(name); + } + /* * Convert an array of signers into an array of concatenated certificate * arrays. @@ -444,4 +484,393 @@ class JarVerifier { } } + + // Extended JavaUtilJarAccess CodeSource API Support + + private Map urlToCodeSourceMap = new HashMap(); + private Map signerToCodeSource = new HashMap(); + private URL lastURL; + private Map lastURLMap; + + /* + * Create a unique mapping from codeSigner cache entries to CodeSource. + * In theory, multiple URLs origins could map to a single locally cached + * and shared JAR file although in practice there will be a single URL in use. + */ + private synchronized CodeSource mapSignersToCodeSource(URL url, CodeSigner[] signers) { + Map map; + if (url == lastURL) { + map = lastURLMap; + } else { + map = (Map) urlToCodeSourceMap.get(url); + if (map == null) { + map = new HashMap(); + urlToCodeSourceMap.put(url, map); + } + lastURLMap = map; + lastURL = url; + } + CodeSource cs = (CodeSource) map.get(signers); + if (cs == null) { + cs = new VerifierCodeSource(csdomain, url, signers); + signerToCodeSource.put(signers, cs); + } + return cs; + } + + private CodeSource[] mapSignersToCodeSources(URL url, List signers, boolean unsigned) { + List sources = new ArrayList(); + + for (int i = 0; i < signers.size(); i++) { + sources.add(mapSignersToCodeSource(url, (CodeSigner[]) signers.get(i))); + } + if (unsigned) { + sources.add(mapSignersToCodeSource(url, null)); + } + return (CodeSource[]) sources.toArray(new CodeSource[sources.size()]); + } + private CodeSigner[] emptySigner = new CodeSigner[0]; + + /* + * Match CodeSource to a CodeSigner[] in the signer cache. + */ + private CodeSigner[] findMatchingSigners(CodeSource cs) { + if (cs instanceof VerifierCodeSource) { + VerifierCodeSource vcs = (VerifierCodeSource) cs; + if (vcs.isSameDomain(csdomain)) { + return ((VerifierCodeSource) cs).getPrivateSigners(); + } + } + + /* + * In practice signers should always be optimized above + * but this handles a CodeSource of any type, just in case. + */ + CodeSource[] sources = mapSignersToCodeSources(cs.getLocation(), getJarCodeSigners(), true); + List sourceList = new ArrayList(); + for (int i = 0; i < sources.length; i++) { + sourceList.add(sources[i]); + } + int j = sourceList.indexOf(cs); + if (j != -1) { + CodeSigner[] match; + match = ((VerifierCodeSource) sourceList.get(j)).getPrivateSigners(); + if (match == null) { + match = emptySigner; + } + return match; + } + return null; + } + + /* + * Instances of this class hold uncopied references to internal + * signing data that can be compared by object reference identity. + */ + private static class VerifierCodeSource extends CodeSource { + + URL vlocation; + CodeSigner[] vsigners; + java.security.cert.Certificate[] vcerts; + Object csdomain; + + VerifierCodeSource(Object csdomain, URL location, CodeSigner[] signers) { + super(location, signers); + this.csdomain = csdomain; + vlocation = location; + vsigners = signers; // from signerCache + } + + VerifierCodeSource(Object csdomain, URL location, java.security.cert.Certificate[] certs) { + super(location, certs); + this.csdomain = csdomain; + vlocation = location; + vcerts = certs; // from signerCache + } + + /* + * All VerifierCodeSource instances are constructed based on + * singleton signerCache or signerCacheCert entries for each unique signer. + * No CodeSigner<->Certificate[] conversion is required. + * We use these assumptions to optimize equality comparisons. + */ + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof VerifierCodeSource) { + VerifierCodeSource that = (VerifierCodeSource) obj; + + /* + * Only compare against other per-signer singletons constructed + * on behalf of the same JarFile instance. Otherwise, compare + * things the slower way. + */ + if (isSameDomain(that.csdomain)) { + if (that.vsigners != this.vsigners + || that.vcerts != this.vcerts) { + return false; + } + if (that.vlocation != null) { + return that.vlocation.equals(this.vlocation); + } else if (this.vlocation != null) { + return this.vlocation.equals(that.vlocation); + } else { // both null + return true; + } + } + } + return super.equals(obj); + } + + boolean isSameDomain(Object csdomain) { + return this.csdomain == csdomain; + } + + private CodeSigner[] getPrivateSigners() { + return vsigners; + } + + private java.security.cert.Certificate[] getPrivateCertificates() { + return vcerts; + } + } + private Map signerMap; + + private synchronized Map signerMap() { + if (signerMap == null) { + /* + * Snapshot signer state so it doesn't change on us. We care + * only about the asserted signatures. Verification of + * signature validity happens via the JarEntry apis. + */ + signerMap = new HashMap(verifiedSigners.size() + sigFileSigners.size()); + signerMap.putAll(verifiedSigners); + signerMap.putAll(sigFileSigners); + } + return signerMap; + } + + public synchronized Enumeration entryNames(JarFile jar, final CodeSource[] cs) { + final Map map = signerMap(); + final Iterator itor = map.entrySet().iterator(); + boolean matchUnsigned = false; + + /* + * Grab a single copy of the CodeSigner arrays. Check + * to see if we can optimize CodeSigner equality test. + */ + List req = new ArrayList(cs.length); + for (int i = 0; i < cs.length; i++) { + CodeSigner[] match = findMatchingSigners(cs[i]); + if (match != null) { + if (match.length > 0) { + req.add(match); + } else { + matchUnsigned = true; + } + } + } + + final List signersReq = req; + final Enumeration enum2 = (matchUnsigned) ? unsignedEntryNames(jar) : emptyEnumeration; + + return new Enumeration() { + + String name; + + public boolean hasMoreElements() { + if (name != null) { + return true; + } + + while (itor.hasNext()) { + Map.Entry e = (Map.Entry) itor.next(); + if (signersReq.contains((CodeSigner[]) e.getValue())) { + name = (String) e.getKey(); + return true; + } + } + while (enum2.hasMoreElements()) { + name = (String) enum2.nextElement(); + return true; + } + return false; + } + + public String nextElement() { + if (hasMoreElements()) { + String value = name; + name = null; + return value; + } + throw new NoSuchElementException(); + } + }; + } + + /* + * Like entries() but screens out internal JAR mechanism entries + * and includes signed entries with no ZIP data. + */ + public Enumeration entries2(final JarFile jar, Enumeration e) { + final Map map = new HashMap(); + map.putAll(signerMap()); + final Enumeration enum_ = e; + return new Enumeration() { + + Enumeration signers = null; + JarEntry entry; + + public boolean hasMoreElements() { + if (entry != null) { + return true; + } + while (enum_.hasMoreElements()) { + ZipEntry ze = (ZipEntry) enum_.nextElement(); + if (JarVerifier.isSigningRelated(ze.getName())) { + continue; + } + entry = jar.newEntry(ze); + return true; + } + if (signers == null) { + signers = Collections.enumeration(map.keySet()); + } + while (signers.hasMoreElements()) { + String name = (String) signers.nextElement(); + entry = jar.newEntry(new ZipEntry(name)); + return true; + } + + // Any map entries left? + return false; + } + + public JarEntry nextElement() { + if (hasMoreElements()) { + JarEntry je = entry; + map.remove(je.getName()); + entry = null; + return je; + } + throw new NoSuchElementException(); + } + }; + } + private Enumeration emptyEnumeration = new Enumeration() { + + public boolean hasMoreElements() { + return false; + } + + public String nextElement() { + throw new NoSuchElementException(); + } + }; + + // true if file is part of the signature mechanism itself + static boolean isSigningRelated(String name) { + name = name.toUpperCase(Locale.ENGLISH); + if (!name.startsWith("META-INF/")) { + return false; + } + name = name.substring(9); + if (name.indexOf('/') != -1) { + return false; + } + if (name.endsWith(".DSA") + || name.endsWith(".RSA") + || name.endsWith(".SF") + || name.endsWith(".EC") + || name.startsWith("SIG-") + || name.equals("MANIFEST.MF")) { + return true; + } + return false; + } + + private Enumeration unsignedEntryNames(JarFile jar) { + final Map map = signerMap(); + final Enumeration entries = jar.entries(); + return new Enumeration() { + + String name; + + /* + * Grab entries from ZIP directory but screen out + * metadata. + */ + public boolean hasMoreElements() { + if (name != null) { + return true; + } + while (entries.hasMoreElements()) { + String value; + ZipEntry e = (ZipEntry) entries.nextElement(); + value = e.getName(); + if (e.isDirectory() || isSigningRelated(value)) { + continue; + } + if (map.get(value) == null) { + name = value; + return true; + } + } + return false; + } + + public String nextElement() { + if (hasMoreElements()) { + String value = name; + name = null; + return value; + } + throw new NoSuchElementException(); + } + }; + } + private List jarCodeSigners; + + private synchronized List getJarCodeSigners() { + CodeSigner[] signers; + if (jarCodeSigners == null) { + HashSet set = new HashSet(); + set.addAll(signerMap().values()); + jarCodeSigners = new ArrayList(); + jarCodeSigners.addAll(set); + } + return jarCodeSigners; + } + + public synchronized CodeSource[] getCodeSources(JarFile jar, URL url) { + boolean hasUnsigned = unsignedEntryNames(jar).hasMoreElements(); + + return mapSignersToCodeSources(url, getJarCodeSigners(), hasUnsigned); + } + + public CodeSource getCodeSource(URL url, String name) { + CodeSigner[] signers; + + signers = (CodeSigner[]) signerMap().get(name); + return mapSignersToCodeSource(url, signers); + } + + public CodeSource getCodeSource(URL url, JarFile jar, JarEntry je) { + CodeSigner[] signers; + + return mapSignersToCodeSource(url, getCodeSigners(jar, je)); + } + + public void setEagerValidation(boolean eager) { + eagerValidation = eager; + } + + public synchronized List getManifestDigests() { + return Collections.unmodifiableList(manifestDigests); + } + + static CodeSource getUnsignedCS(URL url) { + return new VerifierCodeSource(null, url, (java.security.cert.Certificate[]) null); + } } diff --git a/src/share/classes/java/util/jar/JavaUtilJarAccessImpl.java b/src/share/classes/java/util/jar/JavaUtilJarAccessImpl.java index bed2b5a77e5df1edd6349ae4bf6d0497162a4a9b..c53ba0c6f5212409cc4a9d089ccc3b961c85856b 100644 --- a/src/share/classes/java/util/jar/JavaUtilJarAccessImpl.java +++ b/src/share/classes/java/util/jar/JavaUtilJarAccessImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,38 @@ package java.util.jar; import java.io.IOException; +import java.net.URL; +import java.security.CodeSource; +import java.util.Enumeration; +import java.util.List; import sun.misc.JavaUtilJarAccess; class JavaUtilJarAccessImpl implements JavaUtilJarAccess { public boolean jarFileHasClassPathAttribute(JarFile jar) throws IOException { return jar.hasClassPathAttribute(); } + + public CodeSource[] getCodeSources(JarFile jar, URL url) { + return jar.getCodeSources(url); + } + + public CodeSource getCodeSource(JarFile jar, URL url, String name) { + return jar.getCodeSource(url, name); + } + + public Enumeration entryNames(JarFile jar, CodeSource[] cs) { + return jar.entryNames(cs); + } + + public Enumeration entries2(JarFile jar) { + return jar.entries2(); + } + + public void setEagerValidation(JarFile jar, boolean eager) { + jar.setEagerValidation(eager); + } + + public List getManifestDigests(JarFile jar) { + return jar.getManifestDigests(); + } } diff --git a/src/share/classes/sun/misc/JarIndex.java b/src/share/classes/sun/misc/JarIndex.java index 39e2eca91d83b8f28536bff729805a97b1ae5b07..f9781d65a0dd5ec41bef283883df8bdd1495e544 100644 --- a/src/share/classes/sun/misc/JarIndex.java +++ b/src/share/classes/sun/misc/JarIndex.java @@ -103,6 +103,19 @@ public class JarIndex { parseJars(files); } + /** + * Returns the jar index, or null if none. + * + * This single parameter version of the method is retained + * for binary compatibility with earlier releases. + * + * @param jar the JAR file to get the index from. + * @exception IOException if an I/O error has occurred. + */ + public static JarIndex getJarIndex(JarFile jar) throws IOException { + return getJarIndex(jar, null); + } + /** * Returns the jar index, or null if none. * diff --git a/src/share/classes/sun/misc/JavaUtilJarAccess.java b/src/share/classes/sun/misc/JavaUtilJarAccess.java index e5e6b608ee88f2d302e20654e4f40ebe8188df75..0f1efd1d2cb52fb20d6fb00fb0f2a75d208c4bff 100644 --- a/src/share/classes/sun/misc/JavaUtilJarAccess.java +++ b/src/share/classes/sun/misc/JavaUtilJarAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,19 @@ package sun.misc; import java.io.IOException; +import java.net.URL; +import java.security.CodeSource; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; import java.util.jar.JarFile; public interface JavaUtilJarAccess { public boolean jarFileHasClassPathAttribute(JarFile jar) throws IOException; + public CodeSource[] getCodeSources(JarFile jar, URL url); + public CodeSource getCodeSource(JarFile jar, URL url, String name); + public Enumeration entryNames(JarFile jar, CodeSource[] cs); + public Enumeration entries2(JarFile jar); + public void setEagerValidation(JarFile jar, boolean eager); + public List getManifestDigests(JarFile jar); } diff --git a/src/share/classes/sun/security/util/SignatureFileVerifier.java b/src/share/classes/sun/security/util/SignatureFileVerifier.java index d3ce9013e1570a1bdf90a597e605f9fcf6526fdc..f60fcb75f8b0e97374d163dc2e0770e54023ceaf 100644 --- a/src/share/classes/sun/security/util/SignatureFileVerifier.java +++ b/src/share/classes/sun/security/util/SignatureFileVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -181,7 +181,8 @@ public class SignatureFileVerifier { * * */ - public void process(Hashtable signers) + public void process(Hashtable signers, + List manifestDigests) throws IOException, SignatureException, NoSuchAlgorithmException, JarException, CertificateException { @@ -190,14 +191,15 @@ public class SignatureFileVerifier { Object obj = null; try { obj = Providers.startJarVerification(); - processImpl(signers); + processImpl(signers, manifestDigests); } finally { Providers.stopJarVerification(obj); } } - private void processImpl(Hashtable signers) + private void processImpl(Hashtable signers, + List manifestDigests) throws IOException, SignatureException, NoSuchAlgorithmException, JarException, CertificateException { @@ -232,7 +234,7 @@ public class SignatureFileVerifier { sf.getEntries().entrySet().iterator(); // see if we can verify the whole manifest first - boolean manifestSigned = verifyManifestHash(sf, md, decoder); + boolean manifestSigned = verifyManifestHash(sf, md, decoder, manifestDigests); // verify manifest main attributes if (!manifestSigned && !verifyManifestMainAttrs(sf, md, decoder)) { @@ -275,7 +277,8 @@ public class SignatureFileVerifier { */ private boolean verifyManifestHash(Manifest sf, ManifestDigester md, - BASE64Decoder decoder) + BASE64Decoder decoder, + List manifestDigests) throws IOException { Attributes mattr = sf.getMainAttributes(); @@ -290,6 +293,8 @@ public class SignatureFileVerifier { // 16 is length of "-Digest-Manifest" String algorithm = key.substring(0, key.length()-16); + manifestDigests.add(key); + manifestDigests.add(se.getValue()); MessageDigest digest = getDigest(algorithm); if (digest != null) { byte[] computedHash = md.manifestDigest(digest);