Home » openjdk-7 » java » util » jar » [javadoc | source]

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

Home » openjdk-7 » java » util » jar » [javadoc | source]