6742654: Code insertion/replacement attacks against signed jars
6911041: JCK api/signaturetest tests fails for Mixed Code PIT builds (b91) for all trains
6921823: JarVerifier csdomain field not initialized
6921839: Update trusted.libraries list
Reviewed-by: dgu
--- a/jdk/make/java/security/Makefile Fri Feb 11 12:20:45 2011 -0800
+++ b/jdk/make/java/security/Makefile Sat Feb 12 05:09:36 2011 +0800
@@ -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 @@
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 @@
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 @@
blacklist: classes $(BLACKLIST_BUILD)
+trustedlibs: classes $(TRUSTEDLIBS_BUILD)
+
$(PROPS_BUILD): $(PROPS_SRC)
$(install-file)
@@ -102,9 +106,12 @@
$(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
--- a/jdk/src/share/classes/java/util/jar/JarFile.java Fri Feb 11 12:20:45 2011 -0800
+++ b/jdk/src/share/classes/java/util/jar/JarFile.java Sat Feb 12 05:09:36 2011 +0800
@@ -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 @@
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 @@
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 @@
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 @@
}
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<String> 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<String>() {
+
+ 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<JarEntry> 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<JarEntry>() {
+
+ 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<String> unsignedEntryNames() {
+ final Enumeration entries = entries();
+ return new Enumeration<String>() {
+
+ 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();
+ }
}
--- a/jdk/src/share/classes/java/util/jar/JarVerifier.java Fri Feb 11 12:20:45 2011 -0800
+++ b/jdk/src/share/classes/java/util/jar/JarVerifier.java Sat Feb 12 05:09:36 2011 +0800
@@ -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 @@
/** 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 @@
sigFileData = new Hashtable(11);
pendingBlocks = new ArrayList();
baos = new ByteArrayOutputStream();
+ manifestDigests = new ArrayList();
}
/**
@@ -247,7 +259,7 @@
}
sfv.setSignatureFile(bytes);
- sfv.process(sigFileSigners);
+ sfv.process(sigFileSigners, manifestDigests);
}
}
return;
@@ -290,7 +302,7 @@
sfv.setSignatureFile(bytes);
}
}
- sfv.process(sigFileSigners);
+ sfv.process(sigFileSigners, manifestDigests);
} catch (IOException ioe) {
// e.g. sun.security.pkcs.ParsingException
@@ -312,12 +324,18 @@
/**
* 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 @@
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 @@
}
}
+
+ // 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<String> 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>() {
+
+ 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<JarEntry> entries2(final JarFile jar, Enumeration e) {
+ final Map map = new HashMap();
+ map.putAll(signerMap());
+ final Enumeration enum_ = e;
+ return new Enumeration<JarEntry>() {
+
+ 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<String>() {
+
+ 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<String> unsignedEntryNames(JarFile jar) {
+ final Map map = signerMap();
+ final Enumeration entries = jar.entries();
+ return new Enumeration<String>() {
+
+ 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);
+ }
}
--- a/jdk/src/share/classes/java/util/jar/JavaUtilJarAccessImpl.java Fri Feb 11 12:20:45 2011 -0800
+++ b/jdk/src/share/classes/java/util/jar/JavaUtilJarAccessImpl.java Sat Feb 12 05:09:36 2011 +0800
@@ -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<String> entryNames(JarFile jar, CodeSource[] cs) {
+ return jar.entryNames(cs);
+ }
+
+ public Enumeration<JarEntry> entries2(JarFile jar) {
+ return jar.entries2();
+ }
+
+ public void setEagerValidation(JarFile jar, boolean eager) {
+ jar.setEagerValidation(eager);
+ }
+
+ public List getManifestDigests(JarFile jar) {
+ return jar.getManifestDigests();
+ }
}
--- a/jdk/src/share/classes/sun/misc/JarIndex.java Fri Feb 11 12:20:45 2011 -0800
+++ b/jdk/src/share/classes/sun/misc/JarIndex.java Sat Feb 12 05:09:36 2011 +0800
@@ -106,6 +106,19 @@
/**
* Returns the jar index, or <code>null</code> 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 <code>null</code> if none.
+ *
* @param jar the JAR file to get the index from.
* @exception IOException if an I/O error has occurred.
*/
--- a/jdk/src/share/classes/sun/misc/JavaUtilJarAccess.java Fri Feb 11 12:20:45 2011 -0800
+++ b/jdk/src/share/classes/sun/misc/JavaUtilJarAccess.java Sat Feb 12 05:09:36 2011 +0800
@@ -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<String> entryNames(JarFile jar, CodeSource[] cs);
+ public Enumeration<JarEntry> entries2(JarFile jar);
+ public void setEagerValidation(JarFile jar, boolean eager);
+ public List getManifestDigests(JarFile jar);
}
--- a/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java Fri Feb 11 12:20:45 2011 -0800
+++ b/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java Sat Feb 12 05:09:36 2011 +0800
@@ -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 void process(Hashtable<String, CodeSigner[]> signers)
+ public void process(Hashtable<String, CodeSigner[]> signers,
+ List manifestDigests)
throws IOException, SignatureException, NoSuchAlgorithmException,
JarException, CertificateException
{
@@ -190,14 +191,15 @@
Object obj = null;
try {
obj = Providers.startJarVerification();
- processImpl(signers);
+ processImpl(signers, manifestDigests);
} finally {
Providers.stopJarVerification(obj);
}
}
- private void processImpl(Hashtable<String, CodeSigner[]> signers)
+ private void processImpl(Hashtable<String, CodeSigner[]> signers,
+ List manifestDigests)
throws IOException, SignatureException, NoSuchAlgorithmException,
JarException, CertificateException
{
@@ -232,7 +234,7 @@
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 @@
*/
private boolean verifyManifestHash(Manifest sf,
ManifestDigester md,
- BASE64Decoder decoder)
+ BASE64Decoder decoder,
+ List manifestDigests)
throws IOException
{
Attributes mattr = sf.getMainAttributes();
@@ -290,6 +293,8 @@
// 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);