build Chain For X509Certificate - Java Security

Java examples for Security:Certificate

Description

build Chain For X509Certificate

Demo Code


import org.apache.log4j.Logger;
import javax.security.auth.x500.X500Principal;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class Main{
    private static transient final Logger log = Logger
            .getLogger(CertificateChainUtil.class);
    public static final boolean ALLOW_LOG_SELF_SIGN_TESTS = false;
    public static List<X509Certificate> buildChainFor(PublicKey key,
            Collection<X509Certificate> certs) {
        final List<X509Certificate> chain = new ArrayList<X509Certificate>(
                certs.size());// www  . ja  v a  2 s.c  o  m

        final X509Certificate subject = getCertificateFor(key, certs);

        if (subject == null)
            throw new IllegalArgumentException(
                    "Cannot find X509Certificate which corresponds to "
                            + key);

        chain.add(subject);

        // Keep going until we find a root certificate (or until the chain can't be continued)
        {
            X509Certificate old = null;
            X509Certificate current = subject;
            while (current != null && (old == null || !old.equals(current))
                    && !isSelfSigned(current)) {
                old = current;
                current = getIssuer(current, certs);

                if (current != null)
                    chain.add(current);
                else {
                    log.warn("{buildChainFor} Building chain for "
                            + certs.size()
                            + " cert[s] but had to stop after "
                            + chain.size()
                            + " because I could not find the issuer for "
                            + old.getSubjectX500Principal());
                    throw new IllegalArgumentException(
                            "Could not determine issuer for certificate: "
                                    + old.getSubjectX500Principal()
                                    + ". Please ensure certificate list contains all certificates back to the CA's self-signed root!");
                }

                if (chain.size() > certs.size()) {
                    log.warn("{buildChainFor} Too many certificates in chain. Chain: "
                            + Arrays.toString(getPrincipals(chain))
                            + ", Source: "
                            + Arrays.toString(getPrincipals(new ArrayList<X509Certificate>(
                                    certs))));

                    throw new IllegalStateException(
                            "Chain build failed: too many certs in chain (greater than number of input certs)! Chain: "
                                    + Arrays.toString(getPrincipals(chain)));
                }
            }
        }

        // Normalise the array
        return normaliseChain(chain);
    }
    public static List<X509Certificate> buildChainFor(KeyPair keypair,
            Collection<X509Certificate> certs) {
        return buildChainFor(keypair.getPublic(), certs);
    }
    public static X509Certificate getCertificateFor(PublicKey publicKey,
            Collection<X509Certificate> certs) {
        // Search through the certs until we find the public key we're looking for
        for (X509Certificate cert : certs) {
            if (cert.getPublicKey().equals(publicKey))
                return cert;
        }

        return null;
    }
    /**
     * Determines if a certificate is a self signed certificate
     *
     * @param certificate
     *       the certificate to test
     *
     * @return true if the certificate is self-signed, otherwise false if the certificate was not self-signed or the certificate
     * signature could not be verified
     */
    public static boolean isSelfSigned(X509Certificate certificate) {
        return isSignedBy(certificate, certificate.getPublicKey());
    }
    public static X509Certificate getIssuer(X509Certificate subject,
            Collection<X509Certificate> certs) {
        for (X509Certificate cert : certs) {
            if (cert.getSubjectX500Principal().equals(
                    subject.getIssuerX500Principal())) {
                if (isSignedBy(subject, cert.getPublicKey())) {
                    return cert;
                }
            }
        }

        return null;
    }
    public static X500Principal[] getPrincipals(List<X509Certificate> chain) {
        if (chain.contains(null))
            throw new IllegalArgumentException(
                    "Certificate chain contains null!");

        X500Principal[] array = new X500Principal[chain.size()];

        for (int i = 0; i < array.length; i++)
            array[i] = chain.get(i).getSubjectX500Principal();

        return array;
    }
    /**
     * Take a chain and return a (Read-only) chain with the root certificate as the first entry
     *
     * @param chain
     *       a chain with the certificates in order (either leading away from root or leading towards root)
     *
     * @return a read-only chain leading away from the root certificate
     *
     * @throws IllegalArgumentException
     *       if the chain is null or empty
     */
    public static List<X509Certificate> normaliseChain(
            List<X509Certificate> chain) {
        return toRootFirst(chain);
    }
    @SuppressWarnings("unused")
    public static boolean isSignedBy(X509Certificate subject,
            PublicKey signer) {
        try {
            subject.verify(signer);

            // if verify does not throw an exception then it's a self-signed certificate
            return true;
        } catch (Exception e) {
            if (ALLOW_LOG_SELF_SIGN_TESTS && log.isTraceEnabled()) {
                final String dn = subject.getIssuerX500Principal()
                        .getName();

                log.trace("{isSignedBy} " + dn + " not signed by " + signer
                        + ":" + e.getMessage(), e);
            }

            return false;
        }

    }
    /**
     * Take a chain and return a (Read-only) chain with the root certificate as the first entry
     *
     * @param chain
     *       a chain with the certificates in order (either leading away from root or leading towards root)
     *
     * @return a read-only chain leading away from the root certificate
     *
     * @throws IllegalArgumentException
     *       if the chain is null or empty
     */
    public static List<X509Certificate> toRootFirst(
            List<X509Certificate> chain) {
        if (chain == null || chain.isEmpty())
            throw new IllegalArgumentException(
                    "Must provide a chain that is non-null and non-empty");

        final List<X509Certificate> out;
        // Sort the list so the root certificate comes first
        if (!isSelfSigned(chain.get(0))) {
            // Copy the chain List so we can modify it
            out = new ArrayList<X509Certificate>(chain);

            Collections.reverse(out);

            // If, even when reversed, the chain doesn't have a root at the start then the chain's invalid
            if (!isSelfSigned(out.get(0))) {
                throw new IllegalArgumentException(
                        "Neither end of the certificate chain has a Root! "
                                + chain);
            }
        } else {
            out = chain;
        }

        return Collections.unmodifiableList(out);
    }
}

Related Tutorials