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

Java example source code file (ReverseBuilder.java)

This example Java source code file (ReverseBuilder.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, certificateexception, certpathvalidatorexception, certstoreexception, collection, debug, hashset, ioexception, list, override, reversestate, security, set, util, x509certificate, x509certselector

The ReverseBuilder.java Java example source code

/*
 * Copyright (c) 2000, 2013, 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.IOException;
import java.security.GeneralSecurityException;
import java.security.Principal;
import java.security.cert.CertificateException;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertStore;
import java.security.cert.CertStoreException;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXCertPathChecker;
import java.security.cert.PKIXParameters;
import java.security.cert.PKIXReason;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.security.cert.X509CertSelector;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;
import java.util.Set;

import javax.security.auth.x500.X500Principal;

import sun.security.provider.certpath.PKIX.BuilderParams;
import sun.security.util.Debug;
import sun.security.x509.Extension;
import static sun.security.x509.PKIXExtensions.*;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
import sun.security.x509.PolicyMappingsExtension;

/**
 * This class represents a reverse builder, which is able to retrieve
 * matching certificates from CertStores and verify a particular certificate
 * against a ReverseState.
 *
 * @since       1.4
 * @author      Sean Mullan
 * @author      Yassir Elley
 */

class ReverseBuilder extends Builder {

    private Debug debug = Debug.getInstance("certpath");

    private final Set<String> initPolicies;

    /**
     * Initialize the builder with the input parameters.
     *
     * @param params the parameter set used to build a certification path
     */
    ReverseBuilder(BuilderParams buildParams) {
        super(buildParams);

        Set<String> initialPolicies = buildParams.initialPolicies();
        initPolicies = new HashSet<String>();
        if (initialPolicies.isEmpty()) {
            // if no initialPolicies are specified by user, set
            // initPolicies to be anyPolicy by default
            initPolicies.add(PolicyChecker.ANY_POLICY);
        } else {
            initPolicies.addAll(initialPolicies);
        }
    }

    /**
     * Retrieves all certs from the specified CertStores that satisfy the
     * requirements specified in the parameters and the current
     * PKIX state (name constraints, policy constraints, etc).
     *
     * @param currentState the current state.
     *        Must be an instance of <code>ReverseState
     * @param certStores list of CertStores
     */
    @Override
    Collection<X509Certificate> getMatchingCerts
        (State currState, List<CertStore> certStores)
        throws CertStoreException, CertificateException, IOException
    {
        ReverseState currentState = (ReverseState) currState;

        if (debug != null)
            debug.println("In ReverseBuilder.getMatchingCerts.");

        /*
         * The last certificate could be an EE or a CA certificate
         * (we may be building a partial certification path or
         * establishing trust in a CA).
         *
         * Try the EE certs before the CA certs. It will be more
         * common to build a path to an end entity.
         */
        Collection<X509Certificate> certs =
            getMatchingEECerts(currentState, certStores);
        certs.addAll(getMatchingCACerts(currentState, certStores));

        return certs;
    }

    /*
     * Retrieves all end-entity certificates which satisfy constraints
     * and requirements specified in the parameters and PKIX state.
     */
    private Collection<X509Certificate> getMatchingEECerts
        (ReverseState currentState, List<CertStore> certStores)
        throws CertStoreException, CertificateException, IOException {

        /*
         * Compose a CertSelector to filter out
         * certs which do not satisfy requirements.
         *
         * First, retrieve clone of current target cert constraints, and
         * then add more selection criteria based on current validation state.
         */
        X509CertSelector sel = (X509CertSelector) targetCertConstraints.clone();

        /*
         * Match on issuer (subject of previous cert)
         */
        sel.setIssuer(currentState.subjectDN);

        /*
         * Match on certificate validity date.
         */
        sel.setCertificateValid(buildParams.date());

        /*
         * Policy processing optimizations
         */
        if (currentState.explicitPolicy == 0)
            sel.setPolicy(getMatchingPolicies());

        /*
         * If previous cert has a subject key identifier extension,
         * use it to match on authority key identifier extension.
         */
        /*if (currentState.subjKeyId != null) {
          AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(
                (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID),
                null, null);
        sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());
        }*/

        /*
         * Require EE certs
         */
        sel.setBasicConstraints(-2);

        /* Retrieve matching certs from CertStores */
        HashSet<X509Certificate> eeCerts = new HashSet<>();
        addMatchingCerts(sel, certStores, eeCerts, true);

        if (debug != null) {
            debug.println("ReverseBuilder.getMatchingEECerts got "
                          + eeCerts.size() + " certs.");
        }
        return eeCerts;
    }

    /*
     * Retrieves all CA certificates which satisfy constraints
     * and requirements specified in the parameters and PKIX state.
     */
    private Collection<X509Certificate> getMatchingCACerts
        (ReverseState currentState, List<CertStore> certStores)
        throws CertificateException, CertStoreException, IOException {

        /*
         * Compose a CertSelector to filter out
         * certs which do not satisfy requirements.
         */
        X509CertSelector sel = new X509CertSelector();

        /*
         * Match on issuer (subject of previous cert)
         */
        sel.setIssuer(currentState.subjectDN);

        /*
         * Match on certificate validity date.
         */
        sel.setCertificateValid(buildParams.date());

        /*
         * Match on target subject name (checks that current cert's
         * name constraints permit it to certify target).
         * (4 is the integer type for DIRECTORY name).
         */
        byte[] subject = targetCertConstraints.getSubjectAsBytes();
        if (subject != null) {
            sel.addPathToName(4, subject);
        } else {
            X509Certificate cert = targetCertConstraints.getCertificate();
            if (cert != null) {
                sel.addPathToName(4,
                                  cert.getSubjectX500Principal().getEncoded());
            }
        }

        /*
         * Policy processing optimizations
         */
        if (currentState.explicitPolicy == 0)
            sel.setPolicy(getMatchingPolicies());

        /*
         * If previous cert has a subject key identifier extension,
         * use it to match on authority key identifier extension.
         */
        /*if (currentState.subjKeyId != null) {
          AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(
                (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID),
                                null, null);
          sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());
        }*/

        /*
         * Require CA certs
         */
        sel.setBasicConstraints(0);

        /* Retrieve matching certs from CertStores */
        ArrayList<X509Certificate> reverseCerts = new ArrayList<>();
        addMatchingCerts(sel, certStores, reverseCerts, true);

        /* Sort remaining certs using name constraints */
        Collections.sort(reverseCerts, new PKIXCertComparator());

        if (debug != null)
            debug.println("ReverseBuilder.getMatchingCACerts got " +
                          reverseCerts.size() + " certs.");
        return reverseCerts;
    }

    /*
     * This inner class compares 2 PKIX certificates according to which
     * should be tried first when building a path to the target. For
     * now, the algorithm is to look at name constraints in each cert and those
     * which constrain the path closer to the target should be
     * ranked higher. Later, we may want to consider other components,
     * such as key identifiers.
     */
    class PKIXCertComparator implements Comparator<X509Certificate> {

        private Debug debug = Debug.getInstance("certpath");

        @Override
        public int compare(X509Certificate cert1, X509Certificate cert2) {

            /*
             * if either cert certifies the target, always
             * put at head of list.
             */
            X500Principal targetSubject = buildParams.targetSubject();
            if (cert1.getSubjectX500Principal().equals(targetSubject)) {
                return -1;
            }
            if (cert2.getSubjectX500Principal().equals(targetSubject)) {
                return 1;
            }

            int targetDist1;
            int targetDist2;
            try {
                X500Name targetSubjectName = X500Name.asX500Name(targetSubject);
                targetDist1 = Builder.targetDistance(
                    null, cert1, targetSubjectName);
                targetDist2 = Builder.targetDistance(
                    null, cert2, targetSubjectName);
            } catch (IOException e) {
                if (debug != null) {
                    debug.println("IOException in call to Builder.targetDistance");
                    e.printStackTrace();
                }
                throw new ClassCastException
                    ("Invalid target subject distinguished name");
            }

            if (targetDist1 == targetDist2)
                return 0;

            if (targetDist1 == -1)
                return 1;

            if (targetDist1 < targetDist2)
                return -1;

            return 1;
        }
    }

    /**
     * Verifies a matching certificate.
     *
     * This method executes any of the validation steps in the PKIX path validation
     * algorithm which were not satisfied via filtering out non-compliant
     * certificates with certificate matching rules.
     *
     * If the last certificate is being verified (the one whose subject
     * matches the target subject, then the steps in Section 6.1.4 of the
     * Certification Path Validation algorithm are NOT executed,
     * regardless of whether or not the last cert is an end-entity
     * cert or not. This allows callers to certify CA certs as
     * well as EE certs.
     *
     * @param cert the certificate to be verified
     * @param currentState the current state against which the cert is verified
     * @param certPathList the certPathList generated thus far
     */
    @Override
    void verifyCert(X509Certificate cert, State currState,
        List<X509Certificate> certPathList)
        throws GeneralSecurityException
    {
        if (debug != null) {
            debug.println("ReverseBuilder.verifyCert(SN: "
                + Debug.toHexString(cert.getSerialNumber())
                + "\n  Subject: " + cert.getSubjectX500Principal() + ")");
        }

        ReverseState currentState = (ReverseState) currState;

        /* we don't perform any validation of the trusted cert */
        if (currentState.isInitial()) {
            return;
        }

        // Don't bother to verify untrusted certificate more.
        currentState.untrustedChecker.check(cert,
                                    Collections.<String>emptySet());

        /*
         * check for looping - abort a loop if
         * ((we encounter the same certificate twice) AND
         * ((policyMappingInhibited = true) OR (no policy mapping
         * extensions can be found between the occurrences of the same
         * certificate)))
         * in order to facilitate the check to see if there are
         * any policy mapping extensions found between the occurrences
         * of the same certificate, we reverse the certpathlist first
         */
        if ((certPathList != null) && (!certPathList.isEmpty())) {
            List<X509Certificate> reverseCertList = new ArrayList<>();
            for (X509Certificate c : certPathList) {
                reverseCertList.add(0, c);
            }

            boolean policyMappingFound = false;
            for (X509Certificate cpListCert : reverseCertList) {
                X509CertImpl cpListCertImpl = X509CertImpl.toImpl(cpListCert);
                PolicyMappingsExtension policyMappingsExt =
                        cpListCertImpl.getPolicyMappingsExtension();
                if (policyMappingsExt != null) {
                    policyMappingFound = true;
                }
                if (debug != null)
                    debug.println("policyMappingFound = " + policyMappingFound);
                if (cert.equals(cpListCert)) {
                    if ((buildParams.policyMappingInhibited()) ||
                        (!policyMappingFound)){
                        if (debug != null)
                            debug.println("loop detected!!");
                        throw new CertPathValidatorException("loop detected");
                    }
                }
            }
        }

        /* check if target cert */
        boolean finalCert = cert.getSubjectX500Principal().equals(buildParams.targetSubject());

        /* check if CA cert */
        boolean caCert = (cert.getBasicConstraints() != -1 ? true : false);

        /* if there are more certs to follow, verify certain constraints */
        if (!finalCert) {

            /* check if CA cert */
            if (!caCert)
                throw new CertPathValidatorException("cert is NOT a CA cert");

            /* If the certificate was not self-issued, verify that
             * remainingCerts is greater than zero
             */
            if ((currentState.remainingCACerts <= 0) && !X509CertImpl.isSelfIssued(cert)) {
                    throw new CertPathValidatorException
                        ("pathLenConstraint violated, path too long", null,
                         null, -1, PKIXReason.PATH_TOO_LONG);
            }

            /*
             * Check keyUsage extension (only if CA cert and not final cert)
             */
            KeyChecker.verifyCAKeyUsage(cert);

        } else {

            /*
             * If final cert, check that it satisfies specified target
             * constraints
             */
            if (targetCertConstraints.match(cert) == false) {
                throw new CertPathValidatorException("target certificate " +
                    "constraints check failed");
            }
        }

        /*
         * Check revocation.
         */
        if (buildParams.revocationEnabled() && currentState.revChecker != null) {
            currentState.revChecker.check(cert, Collections.<String>emptySet());
        }

        /* Check name constraints if this is not a self-issued cert */
        if (finalCert || !X509CertImpl.isSelfIssued(cert)){
            if (currentState.nc != null) {
                try {
                    if (!currentState.nc.verify(cert)){
                        throw new CertPathValidatorException
                            ("name constraints check failed", null, null, -1,
                             PKIXReason.INVALID_NAME);
                    }
                } catch (IOException ioe) {
                    throw new CertPathValidatorException(ioe);
                }
            }
        }

        /*
         * Check policy
         */
        X509CertImpl certImpl = X509CertImpl.toImpl(cert);
        currentState.rootNode = PolicyChecker.processPolicies
            (currentState.certIndex, initPolicies,
            currentState.explicitPolicy, currentState.policyMapping,
            currentState.inhibitAnyPolicy,
            buildParams.policyQualifiersRejected(), currentState.rootNode,
            certImpl, finalCert);

        /*
         * Check CRITICAL private extensions
         */
        Set<String> unresolvedCritExts = cert.getCriticalExtensionOIDs();
        if (unresolvedCritExts == null) {
            unresolvedCritExts = Collections.<String>emptySet();
        }

        /*
         * Check that the signature algorithm is not disabled.
         */
        currentState.algorithmChecker.check(cert, unresolvedCritExts);

        for (PKIXCertPathChecker checker : currentState.userCheckers) {
            checker.check(cert, unresolvedCritExts);
        }

        /*
         * Look at the remaining extensions and remove any ones we have
         * already checked. If there are any left, throw an exception!
         */
        if (!unresolvedCritExts.isEmpty()) {
            unresolvedCritExts.remove(BasicConstraints_Id.toString());
            unresolvedCritExts.remove(NameConstraints_Id.toString());
            unresolvedCritExts.remove(CertificatePolicies_Id.toString());
            unresolvedCritExts.remove(PolicyMappings_Id.toString());
            unresolvedCritExts.remove(PolicyConstraints_Id.toString());
            unresolvedCritExts.remove(InhibitAnyPolicy_Id.toString());
            unresolvedCritExts.remove(SubjectAlternativeName_Id.toString());
            unresolvedCritExts.remove(KeyUsage_Id.toString());
            unresolvedCritExts.remove(ExtendedKeyUsage_Id.toString());

            if (!unresolvedCritExts.isEmpty())
                throw new CertPathValidatorException
                    ("Unrecognized critical extension(s)", null, null, -1,
                     PKIXReason.UNRECOGNIZED_CRIT_EXT);
        }

        /*
         * Check signature.
         */
        if (buildParams.sigProvider() != null) {
            cert.verify(currentState.pubKey, buildParams.sigProvider());
        } else {
            cert.verify(currentState.pubKey);
        }
    }

    /**
     * Verifies whether the input certificate completes the path.
     * This checks whether the cert is the target certificate.
     *
     * @param cert the certificate to test
     * @return a boolean value indicating whether the cert completes the path.
     */
    @Override
    boolean isPathCompleted(X509Certificate cert) {
        return cert.getSubjectX500Principal().equals(buildParams.targetSubject());
    }

    /** Adds the certificate to the certPathList
     *
     * @param cert the certificate to be added
     * @param certPathList the certification path list
     */
    @Override
    void addCertToPath(X509Certificate cert,
        LinkedList<X509Certificate> certPathList) {
        certPathList.addLast(cert);
    }

    /** Removes final certificate from the certPathList
     *
     * @param certPathList the certification path list
     */
    @Override
    void removeFinalCertFromPath(LinkedList<X509Certificate> certPathList) {
        certPathList.removeLast();
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java ReverseBuilder.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.