public static List<X509Certificate> order( Collection<X509Certificate> certificates ) throws CertificateException
    {
        final LinkedList<X509Certificate> orderedResult = new LinkedList<>();

        if ( certificates.isEmpty() ) {
            return orderedResult;
        }

        if (certificates.size() == 1) {
            orderedResult.addAll( certificates );
            return orderedResult;
        }

        final Map<Principal, X509Certificate> byIssuer = new HashMap<>();
        final Map<Principal, X509Certificate> bySubject = new HashMap<>();

        for ( final X509Certificate certificate : certificates ) {
            final Principal issuer = certificate.getIssuerDN();
            final Principal subject = certificate.getSubjectDN();

            // By issuer
            if ( issuer.equals( subject ))
            {
                // self-signed: use null key.
                final X509Certificate sameIssuer = byIssuer.put( null, certificate );
                if ( sameIssuer != null )
                {
                    throw new CertificateException( "The provided input should not contain multiple root CA certificates. Issuer of first detected Root CA certificate: " + issuer + " Issuer of second detected Root CA certificate: : " + sameIssuer );
                }
            }
            else
            {
                // regular issuer
                if ( byIssuer.put( issuer, certificate ) != null )
                {
                    throw new CertificateException( "The provided input should not contain multiple certificates with identical issuerDN values. Offending value: " + issuer );
                }
            }

            // By subject
            if ( bySubject.put( subject, certificate ) != null ) {
                throw new CertificateException( "The provided input should not contain multiple certificates with identical subjectDN values. Offending value: " + subject );
            }
        }

        // The first certificate will have a 'subject' value that's not an 'issuer' of any other chain.
        X509Certificate first = null;
        for ( Map.Entry<Principal, X509Certificate> entry : bySubject.entrySet() ) {
            final Principal subject = entry.getKey();
            final X509Certificate certificate = entry.getValue();

            if ( ! byIssuer.containsKey( subject ) ) {
                if (first == null) {
                    first = certificate;
                } else {
                    throw new CertificateException( "The provided input should not contain more than one certificates that has a subjectDN value that's not equal to the issuerDN value of another certificate." );
                }
            }
        }

        if (first == null) {
            throw new CertificateException( "The provided input should contain a certificate that has a subjectDN value that's not equal to the issuerDN value of any other certificate." );
        }

        orderedResult.add( first );

        // With the first certificate in hand, every following certificate should have a subject that's equal to the previous issuer value.
        X509Certificate next = bySubject.remove( first.getIssuerDN() );
        while (next != null) {
            orderedResult.add( next );
            next = bySubject.remove( next.getIssuerDN() );
        }

        // final check
        if (orderedResult.size() != certificates.size()) {
            throw new CertificateException( "Unable to recreate a certificate chain from the provided input." );
        }

        return orderedResult;
    }
Orders certificates, starting from the entity to be validated and progressing back toward the CA root.

This implementation matches "issuers" to "subjects" of certificates in such a way that "issuer" value of a
certificate matches the "subject" value of the next certificate.

When certificates are provided that do not belong to the same chain, a CertificateException is thrown.

@param certificates an unordered collection of certificates (cannot be null).
@return An ordered list of certificates (possibly empty, but never null).
@throws CertificateException if there were multiple CA root certs
xmppserver/src/main/java/org/jivesoftware/openfire/keystore/CertificateUtils.java