public class

JarVerifierStream

extends ZipInputStream
/*
 * Copyright (c) 1996, 2004, 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
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.tools.jar;

import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.util.jar.*;
import java.security.cert.Certificate;
import java.security.AccessController;
import java.security.cert.X509Certificate;
import java.security.Identity;
import java.security.PublicKey;
import java.security.Principal;
import sun.security.provider.SystemIdentity;

/**
 * This is OBSOLETE. DO NOT USE THIS. Use
 * java.util.jar.JarEntry.getCertificates instead. It has to stay here
 * because some apps (namely HJ and HJV) call directly into it.
 *
 * This class is stripped down greatly from JDK 1.1.x.
 *
 * @author Roland Schemers
 */
public class JarVerifierStream extends ZipInputStream {

    private JarEntry current;
    private Hashtable verified = new Hashtable();
    private JarInputStream jis;
    private sun.tools.jar.Manifest man = null;

    /**
     * construct a JarVerfierStream from an input stream.
     */
    public JarVerifierStream(InputStream is)
         throws IOException
    {
        super(is);
        jis = new JarInputStream(is);
    }

    public void close()
        throws IOException
    {
        jis.close();
    }

    public void closeEntry() throws IOException {
        jis.closeEntry();
    }

    /**
     * This method scans to see which entry we're parsing and
     * keeps various state information depending on what type of
     * file is being parsed. Files it treats specially are: <ul>
     *
     * <li>Manifest files. At any point, this stream can be queried
     * for a manifest. If it is present, a Manifest object will be
     * returned.
     *
     * <li>Block Signature file. Like with the manifest, the stream
     * can be queried at any time for all blocks parsed thus far.
     *
     * </ul>
     */
    public synchronized ZipEntry getNextEntry() throws IOException {
        current = (JarEntry) jis.getNextEntry();
        return current;
    }

    /**
     * read a single byte.
     */
    public int read() throws IOException {
        int n = jis.read();
        if (n == -1) {
            addIds();
        }
        return n;
    }

    /**
     * read an array of bytes.
     */
    public int read(byte[] b, int off, int len) throws IOException {
        int n = jis.read(b, off, len);
        if (n == -1) {
            addIds();
        }
        return n;
    }

    private void addIds()
    {

        if (current != null) {
            Certificate[] certs = current.getCertificates();
            if (certs != null) {
                Vector ids = getIds(certs);
                if (ids != null) {
                    verified.put(current.getName(), ids);
                }
            }
        }
    }

    /**
     * Returns a Hashtable mapping filenames to vectors of identities.
     */
    public Hashtable getVerifiedSignatures() {
        /* we may want to return a copy of this at some point.
           For now we simply trust the caller */
        if (verified.isEmpty())
            return null;
        else
            return verified;
    }

    /**
     * Returns an enumeration of PKCS7 blocks. This looks bogus,
     * but Hotjava just checks to see if enumeration is not null
     * to see if anything was signed!
     */
    public Enumeration getBlocks() {
        if (verified.isEmpty()) {
            return null;
        } else {
            return new Enumeration() {
                public boolean hasMoreElements() { return false; }
                public Object nextElement() { return null; }
            };
        }
    }

    /**
     * This method used to be called by various versions of
     * AppletResourceLoader, even though they didn't do anything with
     * the result. We leave them and return null for backwards compatability.
     */
    public Hashtable getNameToHash() {
        return null;
    }

    /**
     * Convert java.util.jar.Manifest object to a sun.tools.jar.Manifest
     * object.
     */

    public sun.tools.jar.Manifest getManifest() {
        if (man == null) {
            try {
                java.util.jar.Manifest jman = jis.getManifest();
                if (jman == null)
                    return null;
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                jman.write(baos);
                byte[] data = baos.toByteArray();
                man = new sun.tools.jar.Manifest(data);
            } catch (IOException ioe) {
                // return null
            }
        }
        return man;
    }

    static class CertCache {
        Certificate [] certs;
        Vector ids;

        boolean equals(Certificate[] certs) {
                if (this.certs == null) {
                    if (certs!= null)
                        return false;
                    else
                        return true;
                }

                if (certs == null)
                    return false;

                boolean match;

                for (int i = 0; i < certs.length; i++) {
                    match = false;
                    for (int j = 0; j < this.certs.length; j++) {
                        if (certs[i].equals(this.certs[j])) {
                            match = true;
                            break;
                        }
                    }
                    if (!match) return false;
                }

                for (int i = 0; i < this.certs.length; i++) {
                    match = false;
                    for (int j = 0; j < certs.length; j++) {
                        if (this.certs[i].equals(certs[j])) {
                            match = true;
                            break;
                        }
                    }
                    if (!match) return false;
                }
                return true;
        }
    }

    private ArrayList certCache = null;


    /**
     * Returns the Identity vector for the given array of Certificates
     */
    protected Vector getIds(Certificate[] certs) {
        if (certs == null)
            return null;

        if (certCache == null)
            certCache = new ArrayList();
        CertCache cc;
        for (int i = 0; i < certCache.size(); i++) {
            cc = (CertCache) certCache.get(i);
            if (cc.equals(certs)) {
                return cc.ids;
            }
        }
        cc = new CertCache();
        cc.certs = certs;

        if (certs.length > 0) {
            for (int i=0; i<certs.length; i++) {
                try {
                    X509Certificate cert = (X509Certificate) certs[i];
                    Principal tmpName = cert.getSubjectDN();
                    final SystemIdentity id = new SystemIdentity(
                                                           tmpName.getName(),
                                                           null);

                    byte[] encoded = cert.getEncoded();
                    final java.security.Certificate oldC =
                        new sun.security.x509.X509Cert(encoded);
                    try {
                        AccessController.doPrivileged(
                         new java.security.PrivilegedExceptionAction() {
                            public Object run()
                                throws java.security.KeyManagementException
                            {
                                id.addCertificate(oldC);
                                return null;
                            }
                        });
                    } catch (java.security.PrivilegedActionException pae) {
                        throw (java.security.KeyManagementException)
                            pae.getException();
                    }
                    if (cc.ids == null)
                        cc.ids = new Vector();
                    cc.ids.addElement(id);
                } catch (java.security.KeyManagementException kme) {
                    // ignore if we can't create Identity
                } catch (IOException ioe) {
                    // ignore if we can't parse
                } catch (java.security.cert.CertificateEncodingException cee) {
                    // ignore if we can't encode
                }
            }
        }
        certCache.add(cc);
        return cc.ids;
    }
}