All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.jce.provider.PKIXAttrCertPathBuilderSpi Maven / Gradle / Ivy

Go to download

The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.6.

There is a newer version: 1.46
Show newest version
package org.bouncycastle.jce.provider;

import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.jce.exception.ExtCertPathBuilderException;
import org.bouncycastle.util.Selector;
import org.bouncycastle.x509.ExtendedPKIXBuilderParameters;
import org.bouncycastle.x509.ExtendedPKIXParameters;
import org.bouncycastle.x509.X509AttributeCertStoreSelector;
import org.bouncycastle.x509.X509AttributeCertificate;
import org.bouncycastle.x509.X509CertStoreSelector;

import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.Principal;
import java.security.PublicKey;
import java.security.cert.CertPath;
import java.security.cert.CertPathBuilderException;
import java.security.cert.CertPathBuilderResult;
import java.security.cert.CertPathBuilderSpi;
import java.security.cert.CertPathParameters;
import java.security.cert.CertPathValidator;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateParsingException;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXCertPathBuilderResult;
import java.security.cert.PKIXCertPathValidatorResult;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class PKIXAttrCertPathBuilderSpi
    extends CertPathBuilderSpi
{

    /**
     * Build and validate a CertPath using the given parameter.
     * 
     * @param params PKIXBuilderParameters object containing all information to
     *            build the CertPath
     */
    public CertPathBuilderResult engineBuild(CertPathParameters params)
            throws CertPathBuilderException, InvalidAlgorithmParameterException
    {
        if (!(params instanceof PKIXBuilderParameters)
                && !(params instanceof ExtendedPKIXBuilderParameters))
        {
            throw new InvalidAlgorithmParameterException(
                    "Parameters must be an instance of "
                            + PKIXBuilderParameters.class.getName() + " or "
                            + ExtendedPKIXBuilderParameters.class.getName()
                            + ".");
        }

        ExtendedPKIXBuilderParameters pkixParams;
        if (params instanceof ExtendedPKIXBuilderParameters)
        {
            pkixParams = (ExtendedPKIXBuilderParameters) params;
        }
        else
        {
            pkixParams = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters
                    .getInstance((PKIXBuilderParameters) params);
        }

        Collection targets;
        Iterator targetIter;
        List certPathList = new ArrayList();
        X509AttributeCertificate cert;

        // search target certificates

        Selector certSelect = pkixParams.getTargetConstraints();
        if (!(certSelect instanceof X509AttributeCertStoreSelector))
        {
            throw new CertPathBuilderException(
                    "TargetConstraints must be an instance of "
                            + X509AttributeCertStoreSelector.class.getName()
                            + " for "+this.getClass().getName()+" class.");
        }

        try
        {
            targets = CertPathValidatorUtilities.findCertificates(certSelect,
                    pkixParams.getStores());
        }
        catch (AnnotatedException e)
        {
            throw new ExtCertPathBuilderException("Error finding target attribute certificate.", e);
        }

        if (targets.isEmpty())
        {
            throw new CertPathBuilderException(
                    "No attribute certificate found matching targetContraints.");
        }

        CertPathBuilderResult result = null;

        // check all potential target certificates
        targetIter = targets.iterator();
        while (targetIter.hasNext() && result == null)
        {
            cert = (X509AttributeCertificate) targetIter.next();
            
            X509CertStoreSelector selector = new X509CertStoreSelector();
            Principal[] principals = cert.getIssuer().getPrincipals();
            Set issuers = new HashSet();
            for (int i = 0; i < principals.length; i++)
            {
                try
                {
                    if (principals[i] instanceof X500Principal)
                    {
                        selector.setSubject(((X500Principal)principals[i]).getEncoded());
                    }
                    issuers.addAll(CertPathValidatorUtilities
                        .findCertificates((Selector) selector, pkixParams
                            .getStores()));
                }
                catch (AnnotatedException e)
                {
                    throw new ExtCertPathBuilderException(
                        "Public key certificate for attribute certificate cannot be searched.",
                        e);
                }
                catch (IOException e)
                {
                    throw new ExtCertPathBuilderException(
                        "cannot encode X500Proncipal.",
                        e);
                }
            }
            if (issuers.isEmpty())
            {
                throw new CertPathBuilderException(
                    "Public key certificate for attribute certificate cannot be found.");
            }
            Iterator it = issuers.iterator();
            while (it.hasNext() && result == null)
            {
                result = build(cert, (X509Certificate)it.next(), pkixParams, certPathList);
            }
        }

        if (result == null && certPathException != null)
        {
            throw new ExtCertPathBuilderException(
                                    "Possible certificate chain could not be validated.",
                                    certPathException);
        }

        if (result == null && certPathException == null)
        {
            throw new CertPathBuilderException(
                    "Unable to find certificate chain.");
        }

        return result;
    }

    private Exception certPathException;

    private CertPathBuilderResult build(X509AttributeCertificate attrCert, X509Certificate tbvCert,
            ExtendedPKIXBuilderParameters pkixParams, List tbvPath)

    {
        // If tbvCert is readily present in tbvPath, it indicates having run
        // into a cycle in the
        // PKI graph.
        if (tbvPath.contains(tbvCert))
        {
            return null;
        }
        // step out, the certificate is not allowed to appear in a certification
        // chain
        if (pkixParams.getExcludedCerts().contains(tbvCert))
        {
            return null;
        }
        // test if certificate path exceeds maximum length
        if (pkixParams.getMaxPathLength() != -1)
        {
            if (tbvPath.size() - 1 > pkixParams.getMaxPathLength())
            {
                return null;
            }
        }

        tbvPath.add(tbvCert);

        CertificateFactory cFact;
        CertPathValidator validator;
        CertPathBuilderResult builderResult = null;

        try
        {
            cFact = CertificateFactory.getInstance("X.509", "BC");
            validator = CertPathValidator.getInstance("PKIX", "BC");
        }
        catch (Exception e)
        {
            // cannot happen
            throw new RuntimeException(
                            "Exception creating support classes.");
        }

        try
        {
            // check wether the issuer of  is a TrustAnchor
            if (findTrustAnchor(tbvCert, pkixParams.getTrustAnchors()) != null)
            {
                CertPath certPath;
                PKIXCertPathValidatorResult result;
                try
                {
                    certPath = cFact.generateCertPath(tbvPath);
                }
                catch (Exception e)
                {
                    throw new AnnotatedException(
                                            "Certification path could not be constructed from certificate list.",
                                            e);
                }

                try
                {
                    result = (PKIXCertPathValidatorResult) validator.validate(
                            certPath, pkixParams);
                }
                catch (Exception e)
                {
                    throw new AnnotatedException(
                                            "Certification path could not be validated.",
                                            e);
                }

                return new PKIXCertPathBuilderResult(certPath, result
                        .getTrustAnchor(), result.getPolicyTree(), result
                        .getPublicKey());

            }
            else
            {
                // add additional X.509 stores from locations in certificate
                try
                {
                    addAdditionalStoresFromAltNames(tbvCert, pkixParams);
                }
                catch (CertificateParsingException e)
                {
                    throw new AnnotatedException(
                                            "No additiontal X.509 stores can be added from certificate locations.",
                                            e);
                }
                Collection issuers = new HashSet();
                // try to get the issuer certificate from one
                // of the stores
                try
                {
                    issuers.addAll(findIssuerCerts(tbvCert, pkixParams
                            .getStores()));
                    if (issuers.isEmpty())
                    {
                        issuers.addAll(findIssuerCerts(tbvCert, pkixParams
                                .getAddionalStores()));
                    }
                }
                catch (AnnotatedException e)
                {
                    throw new AnnotatedException(
                                            "Cannot find issuer certificate for certificate in certification path.",
                                            e);
                }
                if (issuers.isEmpty())
                {
                    throw new AnnotatedException(
                            "No issuer certificate for certificate in certification path found.");
                }
                Iterator it = issuers.iterator();

                while (it.hasNext() && builderResult == null)
                {
                    X509Certificate issuer = (X509Certificate) it.next();
                    // if untrusted self signed certificate continue
                    if (issuer.getIssuerX500Principal().equals(
                            issuer.getSubjectX500Principal()))
                    {
                        continue;
                    }
                    builderResult = build(attrCert, issuer, pkixParams, tbvPath);
                }
            }
        }
        catch (AnnotatedException e)
        {
            certPathException = new AnnotatedException(
                            "No valid certification path could be build.", e);
        }
        if (builderResult == null)
        {
            tbvPath.remove(tbvCert);
        }
        return builderResult;
    }

    private void addAdditionalStoresFromAltNames(X509Certificate cert,
            ExtendedPKIXParameters pkixParams)
            throws CertificateParsingException
    {
        // if in the IssuerAltName extension an URI
        // is given, add an additinal X.509 store
        if (cert.getIssuerAlternativeNames() != null)
        {
            Iterator it = cert.getIssuerAlternativeNames().iterator();
            while (it.hasNext())
            {
                // look for URI
                List list = (List) it.next();
                if (list.get(0).equals(
                        new Integer(GeneralName.uniformResourceIdentifier)))
                {
                    // found
                    String temp = (String) list.get(1);
                    CertPathValidatorUtilities.addAdditionalStoreFromLocation(
                            temp, pkixParams);
                }
            }
        }
    }

    /**
     * Search the given Set of TrustAnchor's for one that is the
     * issuer of the given X.509 certificate.
     * 
     * @param cert The X.509 certificate.
     * @param trustAnchors A Set of TrustAnchor's
     * 
     * @return The TrustAnchor object if found or
     *         null if not.
     * 
     * @exception AnnotatedException if a TrustAnchor was found but the
     *                signature verification on the given certificate has thrown
     *                an exception.
     */
    private TrustAnchor findTrustAnchor(X509Certificate cert, Set trustAnchors)
            throws AnnotatedException
    {
        Iterator iter = trustAnchors.iterator();
        TrustAnchor trust = null;
        PublicKey trustPublicKey = null;
        Exception invalidKeyEx = null;

        X509CertSelector certSelectX509 = new X509CertSelector();

        try
        {
            certSelectX509.setSubject(cert.getIssuerX500Principal()
                    .getEncoded());
        }
        catch (IOException ex)
        {
            throw new AnnotatedException(
                                    "Cannot set subject search criteria for trust anchor.",
                                    ex);
        }

        while (iter.hasNext() && trust == null)
        {
            trust = (TrustAnchor) iter.next();
            if (trust.getTrustedCert() != null)
            {
                if (certSelectX509.match(trust.getTrustedCert()))
                {
                    trustPublicKey = trust.getTrustedCert().getPublicKey();
                }
                else
                {
                    trust = null;
                }
            }
            else if (trust.getCAName() != null
                    && trust.getCAPublicKey() != null)
            {
                try
                {
                    X500Principal certIssuer = cert.getIssuerX500Principal();
                    if (certIssuer.getName().equals(trust.getCAName()))
                    {
                        trustPublicKey = trust.getCAPublicKey();
                    }
                    else
                    {
                        trust = null;
                    }
                }
                catch (IllegalArgumentException ex)
                {
                    trust = null;
                }
            }
            else
            {
                trust = null;
            }

            if (trustPublicKey != null)
            {
                try
                {
                    cert.verify(trustPublicKey);
                }
                catch (Exception ex)
                {
                    invalidKeyEx = ex;
                    trust = null;
                }
            }
        }

        if (trust == null && invalidKeyEx != null)
        {
            throw new AnnotatedException(
                                    "Trust anchor found, but certificate validation failed for certificate.",
                                    invalidKeyEx);
        }

        return trust;
    }

    /**
     * Find the issuer certificates of the given certificate.
     * 
     * @param cert The certificate for which the issuer certificate should be
     *            found.
     * @param certStores A list of X509Store object that will be
     *            searched through.
     * 
     * @return A Collection object containing the issuer
     *         X509Certificates. Never null.
     * 
     * @exception AnnotatedException if the signature verification on the given
     *                certificate fails for all found issuer certificates or an
     *                other error occurrs.
     */
    private Collection findIssuerCerts(X509Certificate cert,
            List certStores) throws AnnotatedException
    {
        X509CertStoreSelector certSelect = new X509CertStoreSelector();
        Set certs = new HashSet();
        try
        {
            certSelect.setSubject(cert.getIssuerX500Principal().getEncoded());
        }
        catch (IOException ex)
        {
            throw new AnnotatedException(
                                    "Subject criteria for certificate selector to find issuer certificate could not be set.",
                                    ex);
        }

        Iterator iter;

        try
        {
            iter = CertPathValidatorUtilities.findCertificates(
                    (Selector) certSelect, certStores).iterator();
        }
        catch (AnnotatedException e)
        {
            throw new AnnotatedException(
                            "Issuer certificate cannot be searched.", e);
        }

        AnnotatedException lastException = null;
        boolean issuerCertFound = false;

        X509Certificate issuer;
        while (iter.hasNext())
        {
            issuer = (X509Certificate) iter.next();
            try
            {
                cert.verify(issuer.getPublicKey());
                certs.add(issuer);
                issuerCertFound = true;
            }
            catch (Exception ex)
            {
                lastException = new AnnotatedException(
                                        "Issued certificate could not be verified with issuer certificate.",
                                        ex);
            }
        }

        if (!issuerCertFound && lastException != null)
        {
            throw new AnnotatedException(
                                    "Issuer certificate found but certificate validation failed for certificate.",
                                    lastException);
        }

        return certs;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy