alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (X509CertPath.java)

This example Java source code file (X509CertPath.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

arraylist, certificateencodingexception, certificateexception, derinputstream, deroutputstream, ioexception, list, override, pkcs7, pkcs7_encoding, pkipath_encoding, string, util, x509certificate, x509certpath

The X509CertPath.java Java example source code

/*
 * Copyright (c) 2000, 2012, 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.security.provider.certpath;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.cert.CertificateEncodingException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertPath;
import java.security.cert.X509Certificate;
import java.util.*;

import sun.security.pkcs.ContentInfo;
import sun.security.pkcs.PKCS7;
import sun.security.pkcs.SignerInfo;
import sun.security.x509.AlgorithmId;
import sun.security.util.DerValue;
import sun.security.util.DerOutputStream;
import sun.security.util.DerInputStream;

/**
 * A {@link java.security.cert.CertPath CertPath} (certification path)
 * consisting exclusively of
 * {@link java.security.cert.X509Certificate X509Certificate}s.
 * <p>
 * By convention, X.509 <code>CertPaths are stored from target
 * to trust anchor.
 * That is, the issuer of one certificate is the subject of the following
 * one. However, unvalidated X.509 <code>CertPaths may not follow
 * this convention. PKIX <code>CertPathValidators will detect any
 * departure from this convention and throw a
 * <code>CertPathValidatorException.
 *
 * @author      Yassir Elley
 * @since       1.4
 */
public class X509CertPath extends CertPath {

    private static final long serialVersionUID = 4989800333263052980L;

    /**
     * List of certificates in this chain
     */
    private List<X509Certificate> certs;

    /**
     * The names of our encodings.  PkiPath is the default.
     */
    private static final String COUNT_ENCODING = "count";
    private static final String PKCS7_ENCODING = "PKCS7";
    private static final String PKIPATH_ENCODING = "PkiPath";

    /**
     * List of supported encodings
     */
    private static final Collection<String> encodingList;

    static {
        List<String> list = new ArrayList<>(2);
        list.add(PKIPATH_ENCODING);
        list.add(PKCS7_ENCODING);
        encodingList = Collections.unmodifiableCollection(list);
    }

    /**
     * Creates an <code>X509CertPath from a List of
     * <code>X509Certificates.
     * <p>
     * The certificates are copied out of the supplied <code>List
     * object.
     *
     * @param certs a <code>List of X509Certificates
     * @exception CertificateException if <code>certs contains an element
     *                      that is not an <code>X509Certificate
     */
    @SuppressWarnings("unchecked")
    public X509CertPath(List<? extends Certificate> certs) throws CertificateException {
        super("X.509");

        // Ensure that the List contains only X509Certificates
        //
        // Note; The certs parameter is not necessarily to be of Certificate
        // for some old code. For compatibility, to make sure the exception
        // is CertificateException, rather than ClassCastException, please
        // don't use
        //     for (Certificate obj : certs)
        for (Object obj : certs) {
            if (obj instanceof X509Certificate == false) {
                throw new CertificateException
                    ("List is not all X509Certificates: "
                    + obj.getClass().getName());
            }
        }

        // Assumes that the resulting List is thread-safe. This is true
        // because we ensure that it cannot be modified after construction
        // and the methods in the Sun JDK 1.4 implementation of ArrayList that
        // allow read-only access are thread-safe.
        this.certs = Collections.unmodifiableList(
                new ArrayList<X509Certificate>((List)certs));
    }

    /**
     * Creates an <code>X509CertPath, reading the encoded form
     * from an <code>InputStream. The data is assumed to be in
     * the default encoding.
     *
     * @param is the <code>InputStream to read the data from
     * @exception CertificateException if an exception occurs while decoding
     */
    public X509CertPath(InputStream is) throws CertificateException {
        this(is, PKIPATH_ENCODING);
    }

    /**
     * Creates an <code>X509CertPath, reading the encoded form
     * from an InputStream. The data is assumed to be in the specified
     * encoding.
     *
     * @param is the <code>InputStream to read the data from
     * @param encoding the encoding used
     * @exception CertificateException if an exception occurs while decoding or
     *   the encoding requested is not supported
     */
    public X509CertPath(InputStream is, String encoding)
            throws CertificateException {
        super("X.509");

        switch (encoding) {
            case PKIPATH_ENCODING:
                certs = parsePKIPATH(is);
                break;
            case PKCS7_ENCODING:
                certs = parsePKCS7(is);
                break;
            default:
                throw new CertificateException("unsupported encoding");
        }
    }

    /**
     * Parse a PKIPATH format CertPath from an InputStream. Return an
     * unmodifiable List of the certificates.
     *
     * @param is the <code>InputStream to read the data from
     * @return an unmodifiable List of the certificates
     * @exception CertificateException if an exception occurs
     */
    private static List<X509Certificate> parsePKIPATH(InputStream is)
            throws CertificateException {
        List<X509Certificate> certList = null;
        CertificateFactory certFac = null;

        if (is == null) {
            throw new CertificateException("input stream is null");
        }

        try {
            DerInputStream dis = new DerInputStream(readAllBytes(is));
            DerValue[] seq = dis.getSequence(3);
            if (seq.length == 0) {
                return Collections.<X509Certificate>emptyList();
            }

            certFac = CertificateFactory.getInstance("X.509");
            certList = new ArrayList<X509Certificate>(seq.length);

            // append certs in reverse order (target to trust anchor)
            for (int i = seq.length-1; i >= 0; i--) {
                certList.add((X509Certificate)certFac.generateCertificate
                    (new ByteArrayInputStream(seq[i].toByteArray())));
            }

            return Collections.unmodifiableList(certList);

        } catch (IOException ioe) {
            throw new CertificateException("IOException parsing PkiPath data: "
                    + ioe, ioe);
        }
    }

    /**
     * Parse a PKCS#7 format CertPath from an InputStream. Return an
     * unmodifiable List of the certificates.
     *
     * @param is the <code>InputStream to read the data from
     * @return an unmodifiable List of the certificates
     * @exception CertificateException if an exception occurs
     */
    private static List<X509Certificate> parsePKCS7(InputStream is)
            throws CertificateException {
        List<X509Certificate> certList;

        if (is == null) {
            throw new CertificateException("input stream is null");
        }

        try {
            if (is.markSupported() == false) {
                // Copy the entire input stream into an InputStream that does
                // support mark
                is = new ByteArrayInputStream(readAllBytes(is));
            }
            PKCS7 pkcs7 = new PKCS7(is);

            X509Certificate[] certArray = pkcs7.getCertificates();
            // certs are optional in PKCS #7
            if (certArray != null) {
                certList = Arrays.asList(certArray);
            } else {
                // no certs provided
                certList = new ArrayList<X509Certificate>(0);
            }
        } catch (IOException ioe) {
            throw new CertificateException("IOException parsing PKCS7 data: " +
                                        ioe);
        }
        // Assumes that the resulting List is thread-safe. This is true
        // because we ensure that it cannot be modified after construction
        // and the methods in the Sun JDK 1.4 implementation of ArrayList that
        // allow read-only access are thread-safe.
        return Collections.unmodifiableList(certList);
    }

    /*
     * Reads the entire contents of an InputStream into a byte array.
     *
     * @param is the InputStream to read from
     * @return the bytes read from the InputStream
     */
    private static byte[] readAllBytes(InputStream is) throws IOException {
        byte[] buffer = new byte[8192];
        ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
        int n;
        while ((n = is.read(buffer)) != -1) {
            baos.write(buffer, 0, n);
        }
        return baos.toByteArray();
    }

    /**
     * Returns the encoded form of this certification path, using the
     * default encoding.
     *
     * @return the encoded bytes
     * @exception CertificateEncodingException if an encoding error occurs
     */
    @Override
    public byte[] getEncoded() throws CertificateEncodingException {
        // @@@ Should cache the encoded form
        return encodePKIPATH();
    }

    /**
     * Encode the CertPath using PKIPATH format.
     *
     * @return a byte array containing the binary encoding of the PkiPath object
     * @exception CertificateEncodingException if an exception occurs
     */
    private byte[] encodePKIPATH() throws CertificateEncodingException {

        ListIterator<X509Certificate> li = certs.listIterator(certs.size());
        try {
            DerOutputStream bytes = new DerOutputStream();
            // encode certs in reverse order (trust anchor to target)
            // according to PkiPath format
            while (li.hasPrevious()) {
                X509Certificate cert = li.previous();
                // check for duplicate cert
                if (certs.lastIndexOf(cert) != certs.indexOf(cert)) {
                    throw new CertificateEncodingException
                        ("Duplicate Certificate");
                }
                // get encoded certificates
                byte[] encoded = cert.getEncoded();
                bytes.write(encoded);
            }

            // Wrap the data in a SEQUENCE
            DerOutputStream derout = new DerOutputStream();
            derout.write(DerValue.tag_SequenceOf, bytes);
            return derout.toByteArray();

        } catch (IOException ioe) {
           throw new CertificateEncodingException("IOException encoding " +
                   "PkiPath data: " + ioe, ioe);
        }
    }

    /**
     * Encode the CertPath using PKCS#7 format.
     *
     * @return a byte array containing the binary encoding of the PKCS#7 object
     * @exception CertificateEncodingException if an exception occurs
     */
    private byte[] encodePKCS7() throws CertificateEncodingException {
        PKCS7 p7 = new PKCS7(new AlgorithmId[0],
                             new ContentInfo(ContentInfo.DATA_OID, null),
                             certs.toArray(new X509Certificate[certs.size()]),
                             new SignerInfo[0]);
        DerOutputStream derout = new DerOutputStream();
        try {
            p7.encodeSignedData(derout);
        } catch (IOException ioe) {
            throw new CertificateEncodingException(ioe.getMessage());
        }
        return derout.toByteArray();
    }

    /**
     * Returns the encoded form of this certification path, using the
     * specified encoding.
     *
     * @param encoding the name of the encoding to use
     * @return the encoded bytes
     * @exception CertificateEncodingException if an encoding error occurs or
     *   the encoding requested is not supported
     */
    @Override
    public byte[] getEncoded(String encoding)
            throws CertificateEncodingException {
        switch (encoding) {
            case PKIPATH_ENCODING:
                return encodePKIPATH();
            case PKCS7_ENCODING:
                return encodePKCS7();
            default:
                throw new CertificateEncodingException("unsupported encoding");
        }
    }

    /**
     * Returns the encodings supported by this certification path, with the
     * default encoding first.
     *
     * @return an <code>Iterator over the names of the supported
     *         encodings (as Strings)
     */
    public static Iterator<String> getEncodingsStatic() {
        return encodingList.iterator();
    }

    /**
     * Returns an iteration of the encodings supported by this certification
     * path, with the default encoding first.
     * <p>
     * Attempts to modify the returned <code>Iterator via its
     * <code>remove method result in an
     * <code>UnsupportedOperationException.
     *
     * @return an <code>Iterator over the names of the supported
     *         encodings (as Strings)
     */
    @Override
    public Iterator<String> getEncodings() {
        return getEncodingsStatic();
    }

    /**
     * Returns the list of certificates in this certification path.
     * The <code>List returned must be immutable and thread-safe.
     *
     * @return an immutable <code>List of X509Certificates
     *         (may be empty, but not null)
     */
    @Override
    public List<X509Certificate> getCertificates() {
        return certs;
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java X509CertPath.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.