diff options
Diffstat (limited to 'libjava/classpath/java/util/jar')
| -rw-r--r-- | libjava/classpath/java/util/jar/Attributes.java | 14 | ||||
| -rw-r--r-- | libjava/classpath/java/util/jar/JarEntry.java | 29 | ||||
| -rw-r--r-- | libjava/classpath/java/util/jar/JarFile.java | 212 | ||||
| -rw-r--r-- | libjava/classpath/java/util/jar/Manifest.java | 10 |
4 files changed, 92 insertions, 173 deletions
diff --git a/libjava/classpath/java/util/jar/Attributes.java b/libjava/classpath/java/util/jar/Attributes.java index 92d29cf49b9..329fe6323b7 100644 --- a/libjava/classpath/java/util/jar/Attributes.java +++ b/libjava/classpath/java/util/jar/Attributes.java @@ -67,8 +67,8 @@ import java.util.Set; * @see java.util.jar.Attributes.Name * @author Mark Wielaard (mark@klomp.org) */ -public class Attributes - implements Cloneable, java.util.Map // Fully qualified for jikes 1.22 +public class Attributes + implements Cloneable, Map<Object, Object> { // Fields @@ -78,7 +78,7 @@ public class Attributes * implementation it is actually a Hashtable, but that can be different in * other implementations. */ - protected Map map; + protected Map<Object, Object> map; // Inner class @@ -492,7 +492,7 @@ public class Attributes * * @return a set of attribute name value pairs */ - public Set entrySet() + public Set<Map.Entry<Object, Object>> entrySet() { return map.entrySet(); } @@ -558,7 +558,7 @@ public class Attributes /** * Gives a Set of all the values of defined attribute names. */ - public Set keySet() + public Set<Object> keySet() { return map.keySet(); } @@ -587,7 +587,7 @@ public class Attributes * @exception ClassCastException if the supplied map is not an instance of * Attributes */ - public void putAll(Map attr) + public void putAll(Map<?, ?> attr) { if (!(attr instanceof Attributes)) { @@ -622,7 +622,7 @@ public class Attributes * Returns all the values of the defined attribute name/value pairs as a * Collection. */ - public Collection values() + public Collection<Object> values() { return map.values(); } diff --git a/libjava/classpath/java/util/jar/JarEntry.java b/libjava/classpath/java/util/jar/JarEntry.java index 722a283bba3..515b45fa9b4 100644 --- a/libjava/classpath/java/util/jar/JarEntry.java +++ b/libjava/classpath/java/util/jar/JarEntry.java @@ -1,5 +1,5 @@ /* JarEntry.java - Represents an entry in a jar file - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,6 +39,7 @@ package java.util.jar; import java.io.IOException; import java.security.cert.Certificate; +import java.util.Set; import java.util.zip.ZipEntry; /** @@ -60,7 +61,7 @@ public class JarEntry extends ZipEntry // (Package local) fields Attributes attr; - Certificate certs[]; + JarFile jarfile; // Constructors @@ -79,7 +80,7 @@ public class JarEntry extends ZipEntry { super(name); attr = null; - certs = null; + jarfile = null; } /** @@ -93,7 +94,7 @@ public class JarEntry extends ZipEntry { super(entry); attr = null; - certs = null; + jarfile = null; } /** @@ -112,7 +113,7 @@ public class JarEntry extends ZipEntry catch (IOException _) { } - certs = entry.getCertificates(); + jarfile = entry.jarfile; } // Methods @@ -153,13 +154,19 @@ public class JarEntry extends ZipEntry */ public Certificate[] getCertificates() { - if (certs != null) + if (jarfile != null) { - return (Certificate[])certs.clone(); - } - else - { - return null; + synchronized (jarfile) + { + if (jarfile.entryCerts != null) + { + Set certs = (Set) jarfile.entryCerts.get(getName()); + if (certs != null + && jarfile.verified.get(getName()) == Boolean.TRUE) + return (Certificate[]) certs.toArray(new Certificate[certs.size()]); + } + } } + return null; } } diff --git a/libjava/classpath/java/util/jar/JarFile.java b/libjava/classpath/java/util/jar/JarFile.java index 88814f1d6bf..6807736590a 100644 --- a/libjava/classpath/java/util/jar/JarFile.java +++ b/libjava/classpath/java/util/jar/JarFile.java @@ -68,6 +68,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; @@ -149,6 +151,12 @@ public class JarFile extends ZipFile */ HashMap entryCerts; + /** + * A {@link Map} of message digest algorithm names to their implementation. + * Used to reduce object (algorithm implementation) instantiation. + */ + private HashMap digestAlgorithms = new HashMap(); + static boolean DEBUG = false; static void debug(Object msg) { @@ -313,7 +321,7 @@ public class JarFile extends ZipFile * * @exception IllegalStateException when the JarFile is already closed */ - public Enumeration entries() throws IllegalStateException + public Enumeration<JarEntry> entries() throws IllegalStateException { return new JarEnumeration(super.entries(), this); } @@ -322,13 +330,13 @@ public class JarFile extends ZipFile * Wraps a given Zip Entries Enumeration. For every zip entry a * JarEntry is created and the corresponding Attributes are looked up. */ - private static class JarEnumeration implements Enumeration + private static class JarEnumeration implements Enumeration<JarEntry> { - private final Enumeration entries; + private final Enumeration<? extends ZipEntry> entries; private final JarFile jarfile; - JarEnumeration(Enumeration e, JarFile f) + JarEnumeration(Enumeration<? extends ZipEntry> e, JarFile f) { entries = e; jarfile = f; @@ -339,7 +347,7 @@ public class JarFile extends ZipFile return entries.hasMoreElements(); } - public Object nextElement() + public JarEntry nextElement() { ZipEntry zip = (ZipEntry) entries.nextElement(); JarEntry jar = new JarEntry(zip); @@ -374,19 +382,8 @@ public class JarFile extends ZipFile } jarfile.signaturesRead = true; // fudge it. } - - // Include the certificates only if we have asserted that the - // signatures are valid. This means the certificates will not be - // available if the entry hasn't been read yet. - if (jarfile.entryCerts != null - && jarfile.verified.get(zip.getName()) == Boolean.TRUE) - { - Set certs = (Set) jarfile.entryCerts.get(jar.getName()); - if (certs != null) - jar.certs = (Certificate[]) - certs.toArray(new Certificate[certs.size()]); - } } + jar.jarfile = jarfile; return jar; } } @@ -431,18 +428,7 @@ public class JarFile extends ZipFile } signaturesRead = true; } - // See the comments in the JarEnumeration for why we do this - // check. - if (DEBUG) - debug("entryCerts=" + entryCerts + " verified " + name - + " ? " + verified.get(name)); - if (entryCerts != null && verified.get(name) == Boolean.TRUE) - { - Set certs = (Set) entryCerts.get(name); - if (certs != null) - jarEntry.certs = (Certificate[]) - certs.toArray(new Certificate[certs.size()]); - } + jarEntry.jarfile = this; return jarEntry; } return null; @@ -599,6 +585,31 @@ public class JarFile extends ZipFile validCerts.clear(); } + // Read the manifest into a HashMap (String fileName, String entry) + // The fileName might be split into multiple lines in the manifest. + // Such additional lines will start with a space. + InputStream in = super.getInputStream(super.getEntry(MANIFEST_NAME)); + ByteArrayOutputStream baStream = new ByteArrayOutputStream(); + byte[] ba = new byte[1024]; + while (true) + { + int len = in.read(ba); + if (len < 0) + break; + baStream.write(ba, 0, len); + } + in.close(); + + HashMap hmManifestEntries = new HashMap(); + Pattern p = Pattern.compile("Name: (.+?\r?\n(?: .+?\r?\n)*)" + + ".+?-Digest: .+?\r?\n\r?\n"); + Matcher m = p.matcher(baStream.toString()); + while (m.find()) + { + String fileName = m.group(1).replaceAll("\r?\n ?", ""); + hmManifestEntries.put(fileName, m.group()); + } + // Phase 3: verify the signature file signatures against the manifest, // mapping the entry name to the target certificates. this.entryCerts = new HashMap(); @@ -614,7 +625,7 @@ public class JarFile extends ZipFile Map.Entry e2 = (Map.Entry) it2.next(); String entryname = String.valueOf(e2.getKey()); Attributes attr = (Attributes) e2.getValue(); - if (verifyHashes(entryname, attr)) + if (verifyHashes(entryname, attr, hmManifestEntries)) { if (DEBUG) debug("entry " + entryname + " has certificates " + certificates); @@ -721,39 +732,29 @@ public class JarFile extends ZipFile } /** - * Verifies that the digest(s) in a signature file were, in fact, made - * over the manifest entry for ENTRY. - * + * Verifies that the digest(s) in a signature file were, in fact, made over + * the manifest entry for ENTRY. + * * @param entry The entry name. * @param attr The attributes from the signature file to verify. + * @param hmManifestEntries Mappings of Jar file entry names to their manifest + * entry text; i.e. the base-64 encoding of their */ - private boolean verifyHashes(String entry, Attributes attr) + private boolean verifyHashes(String entry, Attributes attr, + HashMap hmManifestEntries) { int verified = 0; - // The bytes for ENTRY's manifest entry, which are signed in the - // signature file. - byte[] entryBytes = null; - try - { - ZipEntry e = super.getEntry(entry); - if (e == null) - { - if (DEBUG) - debug("verifyHashes: no entry '" + entry + "'"); - return false; - } - entryBytes = readManifestEntry(e); - } - catch (IOException ioe) + String stringEntry = (String) hmManifestEntries.get(entry); + if (stringEntry == null) { if (DEBUG) - { - debug(ioe); - ioe.printStackTrace(); - } + debug("could not find " + entry + " in manifest"); return false; } + // The bytes for ENTRY's manifest entry, which are signed in the + // signature file. + byte[] entryBytes = stringEntry.getBytes(); for (Iterator it = attr.entrySet().iterator(); it.hasNext(); ) { @@ -765,9 +766,14 @@ public class JarFile extends ZipFile try { byte[] hash = Base64InputStream.decode((String) e.getValue()); - MessageDigest md = MessageDigest.getInstance(alg, provider); - md.update(entryBytes); - byte[] hash2 = md.digest(); + MessageDigest md = (MessageDigest) digestAlgorithms.get(alg); + if (md == null) + { + md = MessageDigest.getInstance(alg, provider); + digestAlgorithms.put(alg, md); + } + md.reset(); + byte[] hash2 = md.digest(entryBytes); if (DEBUG) debug("verifying SF entry " + entry + " alg: " + md.getAlgorithm() + " expect=" + new java.math.BigInteger(hash).toString(16) @@ -801,100 +807,6 @@ public class JarFile extends ZipFile } /** - * Read the raw bytes that comprise a manifest entry. We can't use the - * Manifest object itself, because that loses information (such as line - * endings, and order of entries). - */ - private byte[] readManifestEntry(ZipEntry entry) throws IOException - { - InputStream in = super.getInputStream(super.getEntry(MANIFEST_NAME)); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - byte[] target = ("Name: " + entry.getName()).getBytes(); - int t = 0, c, prev = -1, state = 0, l = -1; - - while ((c = in.read()) != -1) - { -// if (DEBUG) -// debug("read " -// + (c == '\n' ? "\\n" : (c == '\r' ? "\\r" : String.valueOf((char) c))) -// + " state=" + state + " prev=" -// + (prev == '\n' ? "\\n" : (prev == '\r' ? "\\r" : String.valueOf((char) prev))) -// + " t=" + t + (t < target.length ? (" target[t]=" + (char) target[t]) : "") -// + " l=" + l); - switch (state) - { - - // Step 1: read until we find the "target" bytes: the start - // of the entry we need to read. - case 0: - if (((byte) c) != target[t]) - t = 0; - else - { - t++; - if (t == target.length) - { - out.write(target); - state = 1; - } - } - break; - - // Step 2: assert that there is a newline character after - // the "target" bytes. - case 1: - if (c != '\n' && c != '\r') - { - out.reset(); - t = 0; - state = 0; - } - else - { - out.write(c); - state = 2; - } - break; - - // Step 3: read this whole entry, until we reach an empty - // line. - case 2: - if (c == '\n') - { - out.write(c); - // NL always terminates a line. - if (l == 0 || (l == 1 && prev == '\r')) - return out.toByteArray(); - l = 0; - } - else - { - // Here we see a blank line terminated by a CR, - // followed by the next entry. Technically, `c' should - // always be 'N' at this point. - if (l == 1 && prev == '\r') - return out.toByteArray(); - out.write(c); - l++; - } - prev = c; - break; - - default: - throw new RuntimeException("this statement should be unreachable"); - } - } - - // The last entry, with a single CR terminating the line. - if (state == 2 && prev == '\r' && l == 0) - return out.toByteArray(); - - // We should not reach this point, we didn't find the entry (or, possibly, - // it is the last entry and is malformed). - throw new IOException("could not find " + entry + " in manifest"); - } - - /** * A utility class that verifies jar entries as they are read. */ private static class EntryInputStream extends FilterInputStream diff --git a/libjava/classpath/java/util/jar/Manifest.java b/libjava/classpath/java/util/jar/Manifest.java index 64a0c476a91..8effc2878ce 100644 --- a/libjava/classpath/java/util/jar/Manifest.java +++ b/libjava/classpath/java/util/jar/Manifest.java @@ -38,7 +38,7 @@ exception statement from your version. */ package java.util.jar; import gnu.java.util.jar.JarUtils; - + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -60,7 +60,7 @@ public class Manifest implements Cloneable private final Attributes mainAttr; /** A map of atrributes for all entries described in this Manifest. */ - private final Map entries; + private final Map<String, Attributes> entries; // Constructors @@ -70,7 +70,7 @@ public class Manifest implements Cloneable public Manifest() { mainAttr = new Attributes(); - entries = new Hashtable(); + entries = new Hashtable<String, Attributes>(); } /** @@ -104,7 +104,7 @@ public class Manifest implements Cloneable public Manifest(Manifest man) { mainAttr = new Attributes(man.getMainAttributes()); - entries = new Hashtable(man.getEntries()); + entries = new Hashtable<String, Attributes>(man.getEntries()); } // Methods @@ -122,7 +122,7 @@ public class Manifest implements Cloneable * in this manifest. Adding, changing or removing from this entries map * changes the entries of this manifest. */ - public Map getEntries() + public Map<String, Attributes> getEntries() { return entries; } |

