Source Code Cross Referenced for JarVerifier.java in  » 6.0-JDK-Core » Collections-Jar-Zip-Logging-regex » java » util » jar » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » Collections Jar Zip Logging regex » java.util.jar 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001        /*
002         * Copyright 1997-2005 Sun Microsystems, Inc.  All Rights Reserved.
003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004         *
005         * This code is free software; you can redistribute it and/or modify it
006         * under the terms of the GNU General Public License version 2 only, as
007         * published by the Free Software Foundation.  Sun designates this
008         * particular file as subject to the "Classpath" exception as provided
009         * by Sun in the LICENSE file that accompanied this code.
010         *
011         * This code is distributed in the hope that it will be useful, but WITHOUT
012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014         * version 2 for more details (a copy is included in the LICENSE file that
015         * accompanied this code).
016         *
017         * You should have received a copy of the GNU General Public License version
018         * 2 along with this work; if not, write to the Free Software Foundation,
019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020         *
021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022         * CA 95054 USA or visit www.sun.com if you need additional information or
023         * have any questions.
024         */
025
026        package java.util.jar;
027
028        import java.io.*;
029        import java.util.*;
030        import java.util.zip.*;
031        import java.security.*;
032        import java.security.cert.CertificateException;
033
034        import sun.security.util.ManifestDigester;
035        import sun.security.util.ManifestEntryVerifier;
036        import sun.security.util.SignatureFileVerifier;
037        import sun.security.util.Debug;
038
039        /**
040         *
041         * @version 	1.44 07/05/05
042         * @author	Roland Schemers
043         */
044        class JarVerifier {
045
046            /* Are we debugging ? */
047            static final Debug debug = Debug.getInstance("jar");
048
049            /* a table mapping names to code signers, for jar entries that have
050               had their actual hashes verified */
051            private Hashtable verifiedSigners;
052
053            /* a table mapping names to code signers, for jar entries that have
054               passed the .SF/.DSA -> MANIFEST check */
055            private Hashtable sigFileSigners;
056
057            /* a hash table to hold .SF bytes */
058            private Hashtable sigFileData;
059
060            /** "queue" of pending PKCS7 blocks that we couldn't parse
061             *  until we parsed the .SF file */
062            private ArrayList pendingBlocks;
063
064            /* cache of CodeSigner objects */
065            private ArrayList signerCache;
066
067            /* Are we parsing a block? */
068            private boolean parsingBlockOrSF = false;
069
070            /* Are we done parsing META-INF entries? */
071            private boolean parsingMeta = true;
072
073            /* Are there are files to verify? */
074            private boolean anyToVerify = true;
075
076            /* The output stream to use when keeping track of files we are interested
077               in */
078            private ByteArrayOutputStream baos;
079
080            /** The ManifestDigester object */
081            private ManifestDigester manDig;
082
083            /** the bytes for the manDig object */
084            byte manifestRawBytes[] = null;
085
086            public JarVerifier(byte rawBytes[]) {
087                manifestRawBytes = rawBytes;
088                sigFileSigners = new Hashtable();
089                verifiedSigners = new Hashtable();
090                sigFileData = new Hashtable(11);
091                pendingBlocks = new ArrayList();
092                baos = new ByteArrayOutputStream();
093            }
094
095            /**
096             * This method scans to see which entry we're parsing and
097             * keeps various state information depending on what type of
098             * file is being parsed.
099             */
100            public void beginEntry(JarEntry je, ManifestEntryVerifier mev)
101                    throws IOException {
102                if (je == null)
103                    return;
104
105                if (debug != null) {
106                    debug.println("beginEntry " + je.getName());
107                }
108
109                String name = je.getName();
110
111                /*
112                 * Assumptions:
113                 * 1. The manifest should be the first entry in the META-INF directory.
114                 * 2. The .SF/.DSA files follow the manifest, before any normal entries
115                 * 3. Any of the following will throw a SecurityException:
116                 *    a. digest mismatch between a manifest section and
117                 *       the SF section.
118                 *    b. digest mismatch between the actual jar entry and the manifest
119                 */
120
121                if (parsingMeta) {
122                    String uname = name.toUpperCase(Locale.ENGLISH);
123                    if ((uname.startsWith("META-INF/") || uname
124                            .startsWith("/META-INF/"))) {
125
126                        if (je.isDirectory()) {
127                            mev.setEntry(null, je);
128                            return;
129                        }
130
131                        if (SignatureFileVerifier.isBlockOrSF(uname)) {
132                            /* We parse only DSA or RSA PKCS7 blocks. */
133                            parsingBlockOrSF = true;
134                            baos.reset();
135                            mev.setEntry(null, je);
136                        }
137                        return;
138                    }
139                }
140
141                if (parsingMeta) {
142                    doneWithMeta();
143                }
144
145                if (je.isDirectory()) {
146                    mev.setEntry(null, je);
147                    return;
148                }
149
150                // be liberal in what you accept. If the name starts with ./, remove
151                // it as we internally canonicalize it with out the ./.
152                if (name.startsWith("./"))
153                    name = name.substring(2);
154
155                // be liberal in what you accept. If the name starts with /, remove
156                // it as we internally canonicalize it with out the /.
157                if (name.startsWith("/"))
158                    name = name.substring(1);
159
160                // only set the jev object for entries that have a signature
161                if (sigFileSigners.get(name) != null) {
162                    mev.setEntry(name, je);
163                    return;
164                }
165
166                // don't compute the digest for this entry
167                mev.setEntry(null, je);
168
169                return;
170            }
171
172            /**
173             * update a single byte.
174             */
175
176            public void update(int b, ManifestEntryVerifier mev)
177                    throws IOException {
178                if (b != -1) {
179                    if (parsingBlockOrSF) {
180                        baos.write(b);
181                    } else {
182                        mev.update((byte) b);
183                    }
184                } else {
185                    processEntry(mev);
186                }
187            }
188
189            /**
190             * update an array of bytes.
191             */
192
193            public void update(int n, byte[] b, int off, int len,
194                    ManifestEntryVerifier mev) throws IOException {
195                if (n != -1) {
196                    if (parsingBlockOrSF) {
197                        baos.write(b, off, n);
198                    } else {
199                        mev.update(b, off, n);
200                    }
201                } else {
202                    processEntry(mev);
203                }
204            }
205
206            /**
207             * called when we reach the end of entry in one of the read() methods.
208             */
209            private void processEntry(ManifestEntryVerifier mev)
210                    throws IOException {
211                if (!parsingBlockOrSF) {
212                    JarEntry je = mev.getEntry();
213                    if ((je != null) && (je.signers == null)) {
214                        je.signers = mev
215                                .verify(verifiedSigners, sigFileSigners);
216                        je.certs = mapSignersToCertArray(je.signers);
217                    }
218                } else {
219
220                    try {
221                        parsingBlockOrSF = false;
222
223                        if (debug != null) {
224                            debug.println("processEntry: processing block");
225                        }
226
227                        String uname = mev.getEntry().getName().toUpperCase(
228                                Locale.ENGLISH);
229
230                        if (uname.endsWith(".SF")) {
231                            String key = uname.substring(0, uname.length() - 3);
232                            byte bytes[] = baos.toByteArray();
233                            // add to sigFileData in case future blocks need it
234                            sigFileData.put(key, bytes);
235                            // check pending blocks, we can now process
236                            // anyone waiting for this .SF file
237                            Iterator it = pendingBlocks.iterator();
238                            while (it.hasNext()) {
239                                SignatureFileVerifier sfv = (SignatureFileVerifier) it
240                                        .next();
241                                if (sfv.needSignatureFile(key)) {
242                                    if (debug != null) {
243                                        debug
244                                                .println("processEntry: processing pending block");
245                                    }
246
247                                    sfv.setSignatureFile(bytes);
248                                    sfv.process(sigFileSigners);
249                                }
250                            }
251                            return;
252                        }
253
254                        // now we are parsing a signature block file
255
256                        String key = uname.substring(0, uname.lastIndexOf("."));
257
258                        if (signerCache == null)
259                            signerCache = new ArrayList();
260
261                        if (manDig == null) {
262                            synchronized (manifestRawBytes) {
263                                if (manDig == null) {
264                                    manDig = new ManifestDigester(
265                                            manifestRawBytes);
266                                    manifestRawBytes = null;
267                                }
268                            }
269                        }
270
271                        SignatureFileVerifier sfv = new SignatureFileVerifier(
272                                signerCache, manDig, uname, baos.toByteArray());
273
274                        if (sfv.needSignatureFileBytes()) {
275                            // see if we have already parsed an external .SF file
276                            byte[] bytes = (byte[]) sigFileData.get(key);
277
278                            if (bytes == null) {
279                                // put this block on queue for later processing
280                                // since we don't have the .SF bytes yet
281                                // (uname, block);
282                                if (debug != null) {
283                                    debug.println("adding pending block");
284                                }
285                                pendingBlocks.add(sfv);
286                                return;
287                            } else {
288                                sfv.setSignatureFile(bytes);
289                            }
290                        }
291                        sfv.process(sigFileSigners);
292
293                    } catch (sun.security.pkcs.ParsingException pe) {
294                        if (debug != null)
295                            debug.println("processEntry caught: " + pe);
296                        // ignore and treat as unsigned
297                    } catch (IOException ioe) {
298                        if (debug != null)
299                            debug.println("processEntry caught: " + ioe);
300                        // ignore and treat as unsigned
301                    } catch (SignatureException se) {
302                        if (debug != null)
303                            debug.println("processEntry caught: " + se);
304                        // ignore and treat as unsigned
305                    } catch (NoSuchAlgorithmException nsae) {
306                        if (debug != null)
307                            debug.println("processEntry caught: " + nsae);
308                        // ignore and treat as unsigned
309                    } catch (CertificateException ce) {
310                        if (debug != null)
311                            debug.println("processEntry caught: " + ce);
312                        // ignore and treat as unsigned
313                    }
314                }
315            }
316
317            /**
318             * Return an array of java.security.cert.Certificate objects for
319             * the given file in the jar. 
320             */
321            public java.security.cert.Certificate[] getCerts(String name) {
322                return mapSignersToCertArray(getCodeSigners(name));
323            }
324
325            /**
326             * return an array of CodeSigner objects for
327             * the given file in the jar. this array is not cloned.
328             *
329             */
330            public CodeSigner[] getCodeSigners(String name) {
331                return (CodeSigner[]) verifiedSigners.get(name);
332            }
333
334            /*
335             * Convert an array of signers into an array of concatenated certificate 
336             * arrays.
337             */
338            private static java.security.cert.Certificate[] mapSignersToCertArray(
339                    CodeSigner[] signers) {
340
341                if (signers != null) {
342                    ArrayList certChains = new ArrayList();
343                    for (int i = 0; i < signers.length; i++) {
344                        certChains.addAll(signers[i].getSignerCertPath()
345                                .getCertificates());
346                    }
347
348                    // Convert into a Certificate[]
349                    return (java.security.cert.Certificate[]) certChains
350                            .toArray(new java.security.cert.Certificate[certChains
351                                    .size()]);
352                }
353                return null;
354            }
355
356            /**
357             * returns true if there no files to verify.
358             * should only be called after all the META-INF entries
359             * have been processed.
360             */
361            boolean nothingToVerify() {
362                return (anyToVerify == false);
363            }
364
365            /**
366             * called to let us know we have processed all the
367             * META-INF entries, and if we re-read one of them, don't
368             * re-process it. Also gets rid of any data structures
369             * we needed when parsing META-INF entries.
370             */
371            void doneWithMeta() {
372                parsingMeta = false;
373                anyToVerify = !sigFileSigners.isEmpty();
374                baos = null;
375                sigFileData = null;
376                pendingBlocks = null;
377                signerCache = null;
378                manDig = null;
379            }
380
381            static class VerifierStream extends java.io.InputStream {
382
383                private InputStream is;
384                private JarVerifier jv;
385                private ManifestEntryVerifier mev;
386                private long numLeft;
387
388                VerifierStream(Manifest man, JarEntry je, InputStream is,
389                        JarVerifier jv) throws IOException {
390                    this .is = is;
391                    this .jv = jv;
392                    this .mev = new ManifestEntryVerifier(man);
393                    this .jv.beginEntry(je, mev);
394                    this .numLeft = je.getSize();
395                    if (this .numLeft == 0)
396                        this .jv.update(-1, this .mev);
397                }
398
399                public int read() throws IOException {
400                    if (numLeft > 0) {
401                        int b = is.read();
402                        jv.update(b, mev);
403                        numLeft--;
404                        if (numLeft == 0)
405                            jv.update(-1, mev);
406                        return b;
407                    } else {
408                        return -1;
409                    }
410                }
411
412                public int read(byte b[], int off, int len) throws IOException {
413                    if ((numLeft > 0) && (numLeft < len)) {
414                        len = (int) numLeft;
415                    }
416
417                    if (numLeft > 0) {
418                        int n = is.read(b, off, len);
419                        jv.update(n, b, off, len, mev);
420                        numLeft -= n;
421                        if (numLeft == 0)
422                            jv.update(-1, b, off, len, mev);
423                        return n;
424                    } else {
425                        return -1;
426                    }
427                }
428
429                public void close() throws IOException {
430                    if (is != null)
431                        is.close();
432                    is = null;
433                    mev = null;
434                    jv = null;
435                }
436
437                public int available() throws IOException {
438                    return is.available();
439                }
440
441            }
442        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.