New version with the trim() correctly done after the split not before...

2016-09-30 16:04 GMT+02:00 Claude Libois <clibois.w...@gmail.com>:

> Found that it was not possible with Merlin cause it only allow to define a
> single CRL File.
> I have done a quick change that enable a comma separated list of crl.
> Here is the change. Can someone review it and if it's ok add it to the
> official source code ?
> //
>         // Load the CRL file
>         //
>         String crlLocations = properties.getProperty(prefix +
> X509_CRL_FILE);
>         if (crlLocations != null) {
>             crlLocations = crlLocations.trim();
>             String[] splittedCrlsLocation=crlLocations.split(",");
>             List<X509CRL> crls=new ArrayList();
>             for (int i = 0; i < splittedCrlsLocation.length; i++) {
>                 String crlLocation = splittedCrlsLocation[i];
>                 InputStream is = loadInputStream(loader, crlLocation);
>
>                 try {
>                     CertificateFactory cf = getCertificateFactory();
>                     X509CRL crl = (X509CRL)cf.generateCRL(is);
>                     crls.add(crl);
>                 } catch (Exception e) {
>                     if (DO_DEBUG) {
>                         LOG.debug(e.getMessage(), e);
>                     }
>                     throw new WSSecurityException(
> WSSecurityException.ErrorCode.FAILURE, "ioError00", e);
>                 } finally {
>                     if (is != null) {
>                         is.close();
>                     }
>                 }
>             }
>             try {
>                 if (provider == null || provider.length() == 0) {
>                     crlCertStore =
>                             CertStore.getInstance(
>                                     "Collection",
>                                     new CollectionCertStoreParameters(
> crls)
>                             );
>
>                 } else {
>                     crlCertStore =
>                             CertStore.getInstance(
>                                     "Collection",
>                                     new CollectionCertStoreParameters(
> crls),
>                                     provider
>                             );
>                 }
>             } catch (Exception e) {
>                 if (DO_DEBUG) {
>                     LOG.debug(e.getMessage(), e);
>                 }
>                 throw new WSSecurityException(
> WSSecurityException.ErrorCode.FAILURE, "ioError00", e);
>             }
>             if (DO_DEBUG) {
>                 LOG.debug(
>                         "The CRL " + crlLocations + " has been loaded"
>                 );
>             }
> Best Regards,
> Claude
>
> 2016-09-30 15:14 GMT+02:00 Claude Libois <clibois.w...@gmail.com>:
>
>> Hi,
>> I got the following pki chain Root CA>Intermediate CA>Client signing
>> certificate
>> A suggested by Colm, I have set in my truststore my Intermediate CA and
>> my Root CA.
>> However, by doing this, CRL verification doesn't work. In fact, it seems
>> to validate my Intermediate CA against the Root CA crl while I'm only
>> interested to verify the client certificate.
>> I'm not sure how revocation validation works but it seems to validate CRL
>> for every certificate(except the Root).
>> However, I don't know how to specify multiple CRL in WSS4J or if it
>> possible to merge 2 crl files into a common one ?
>> I have provided 2 logs. The first one with the Intermediate CA CRL. We
>> can see that validation of the Intermediate CA against Root CRL failed
>> since it's not provided.
>> The second one is with the Root CA CRL. Intermediate CA validation
>> succeed but the signing certificate then failed...
>>
>> Best Regards,
>> Claude
>>
>
>
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.wss4j.common.crypto;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.x500.X500Principal;

import org.apache.wss4j.common.ext.WSPasswordCallback;
import org.apache.wss4j.common.ext.WSSecurityException;
import org.apache.wss4j.common.util.Loader;

/**
 * A Crypto implementation based on two Java KeyStore objects, one being the keystore, and one
 * being the truststore.
 */
public class Merlin extends CryptoBase {

    public static final String ENCRYPTED_PASSWORD_PREFIX = "ENC(";
    public static final String ENCRYPTED_PASSWORD_SUFFIX = ")";

    public static final String PREFIX = "org.apache.wss4j.crypto.merlin.";
    public static final String OLD_PREFIX = "org.apache.ws.security.crypto.merlin.";

    /*
     * Deprecated types
     */
    public static final String OLD_KEYSTORE_FILE = "file";

    /*
     * Crypto providers
     */
    public static final String CRYPTO_KEYSTORE_PROVIDER = "keystore.provider";
    public static final String CRYPTO_CERT_PROVIDER = "cert.provider";

    /*
     * KeyStore configuration types
     */
    public static final String KEYSTORE_FILE = "keystore.file";
    public static final String KEYSTORE_PASSWORD ="keystore.password";
    public static final String KEYSTORE_TYPE ="keystore.type";
    public static final String KEYSTORE_ALIAS ="keystore.alias";
    public static final String KEYSTORE_PRIVATE_PASSWORD ="keystore.private.password";

    /*
     * TrustStore configuration types
     */
    public static final String LOAD_CA_CERTS ="load.cacerts";
    public static final String TRUSTSTORE_FILE ="truststore.file";
    public static final String TRUSTSTORE_PASSWORD ="truststore.password";
    public static final String TRUSTSTORE_TYPE = "truststore.type";

    /*
     * CRL configuration
     */
    public static final String X509_CRL_FILE = "x509crl.file";

    private static final org.slf4j.Logger LOG =
            org.slf4j.LoggerFactory.getLogger(Merlin.class);
    private static final boolean DO_DEBUG = LOG.isDebugEnabled();

    protected Properties properties;
    protected KeyStore keystore;
    protected KeyStore truststore;
    protected CertStore crlCertStore;
    protected boolean loadCACerts;
    protected boolean privatePasswordSet;
    protected PasswordEncryptor passwordEncryptor;

    public Merlin() {
        // default constructor
    }

    public Merlin(boolean loadCACerts, String cacertsPasswd) {
        super();

        if (truststore == null && loadCACerts) {
            InputStream cacertsIs = null;

            try {
                String cacertsPath = System.getProperty("java.home") + "/lib/security/cacerts";
                cacertsIs = new FileInputStream(cacertsPath);

                truststore = KeyStore.getInstance(KeyStore.getDefaultType());
                truststore.load(cacertsIs, cacertsPasswd.toCharArray());
                loadCACerts = true;
            } catch (Exception e) {
                LOG.warn("CA certs could not be loaded: " + e.getMessage());
            } finally {
                if (cacertsIs != null) {
                    try {
                        cacertsIs.close();
                    } catch (IOException e) {
                        LOG.debug(e.getMessage(), e);
                        //ignore
                    }
                }
            }
        }
    }

    public Merlin(Properties properties, ClassLoader loader, PasswordEncryptor passwordEncryptor)
            throws WSSecurityException, IOException {
        loadProperties(properties, loader, passwordEncryptor);
    }

    public void loadProperties(
            Properties properties,
            ClassLoader loader,
            PasswordEncryptor passwordEncryptor
    ) throws WSSecurityException, IOException {
        if (properties == null) {
            return;
        }
        this.properties = properties;
        this.passwordEncryptor = passwordEncryptor;

        String prefix = PREFIX;
        for (Object key : properties.keySet()) {
            if (key instanceof String) {
                String propKey = (String)key;
                if (propKey.startsWith(PREFIX)) {
                    break;
                } else if (propKey.startsWith(OLD_PREFIX)) {
                    prefix = OLD_PREFIX;
                    break;
                }
            }
        }

        //
        // Load the provider(s)
        //
        String provider = properties.getProperty(prefix + CRYPTO_KEYSTORE_PROVIDER);
        if (provider != null) {
            provider = provider.trim();
        }
        String certProvider = properties.getProperty(prefix + CRYPTO_CERT_PROVIDER);
        if (certProvider != null) {
            setCryptoProvider(certProvider);
        }
        //
        // Load the KeyStore
        //
        String alias = properties.getProperty(prefix + KEYSTORE_ALIAS);
        if (alias != null) {
            alias = alias.trim();
            defaultAlias = alias;
        }
        String keyStoreLocation = properties.getProperty(prefix + KEYSTORE_FILE);
        if (keyStoreLocation == null) {
            keyStoreLocation = properties.getProperty(prefix + OLD_KEYSTORE_FILE);
        }
        if (keyStoreLocation != null) {
            keyStoreLocation = keyStoreLocation.trim();
            InputStream is = loadInputStream(loader, keyStoreLocation);

            try {
                String passwd = properties.getProperty(prefix + KEYSTORE_PASSWORD, "security");
                if (passwd != null) {
                    passwd = passwd.trim();
                    passwd = decryptPassword(passwd, passwordEncryptor);
                }
                String type = properties.getProperty(prefix + KEYSTORE_TYPE, KeyStore.getDefaultType());
                if (type != null) {
                    type = type.trim();
                }
                keystore = load(is, passwd, provider, type);
                if (DO_DEBUG) {
                    LOG.debug(
                            "The KeyStore " + keyStoreLocation + " of type " + type
                                    + " has been loaded"
                    );
                }
                String privatePasswd = properties.getProperty(prefix + KEYSTORE_PRIVATE_PASSWORD);
                if (privatePasswd != null) {
                    privatePasswordSet = true;
                }
            } finally {
                if (is != null) {
                    is.close();
                }
            }
        } else {
            if (DO_DEBUG) {
                LOG.debug("The KeyStore is not loaded as KEYSTORE_FILE is null");
            }
        }

        //
        // Load the TrustStore
        //
        String trustStoreLocation = properties.getProperty(prefix + TRUSTSTORE_FILE);
        if (trustStoreLocation != null) {
            trustStoreLocation = trustStoreLocation.trim();
            InputStream is = loadInputStream(loader, trustStoreLocation);

            try {
                String passwd = properties.getProperty(prefix + TRUSTSTORE_PASSWORD, "changeit");
                if (passwd != null) {
                    passwd = passwd.trim();
                    passwd = decryptPassword(passwd, passwordEncryptor);
                }
                String type = properties.getProperty(prefix + TRUSTSTORE_TYPE, KeyStore.getDefaultType());
                if (type != null) {
                    type = type.trim();
                }
                truststore = load(is, passwd, provider, type);
                if (DO_DEBUG) {
                    LOG.debug(
                            "The TrustStore " + trustStoreLocation + " of type " + type
                                    + " has been loaded"
                    );
                }
                loadCACerts = false;
            } finally {
                if (is != null) {
                    is.close();
                }
            }
        } else {
            String loadCacerts = properties.getProperty(prefix + LOAD_CA_CERTS, "false");
            if (loadCacerts != null) {
                loadCacerts = loadCacerts.trim();
            }
            if (Boolean.valueOf(loadCacerts)) {
                String cacertsPath = System.getProperty("java.home") + "/lib/security/cacerts";
                if (cacertsPath != null) {
                    cacertsPath = cacertsPath.trim();
                }
                InputStream is = new FileInputStream(cacertsPath);
                try {
                    String cacertsPasswd = properties.getProperty(prefix + TRUSTSTORE_PASSWORD, "changeit");
                    if (cacertsPasswd != null) {
                        cacertsPasswd = cacertsPasswd.trim();
                        cacertsPasswd = decryptPassword(cacertsPasswd, passwordEncryptor);
                    }
                    truststore = load(is, cacertsPasswd, null, KeyStore.getDefaultType());
                    if (DO_DEBUG) {
                        LOG.debug("CA certs have been loaded");
                    }
                    loadCACerts = true;
                } finally {
                    if (is != null) {
                        is.close();
                    }
                }
            }
        }
        //
        // Load the CRL file
        //
        String crlLocations = properties.getProperty(prefix + X509_CRL_FILE);
        if (crlLocations != null) {
            String[] splittedCrlsLocation=crlLocations.split(",");
            List<X509CRL> crls=new ArrayList();
            for (int i = 0; i < splittedCrlsLocation.length; i++) {
                String crlLocation = splittedCrlsLocation[i];
                crlLocation = crlLocation.trim();
                InputStream is = loadInputStream(loader, crlLocation);

                try {
                    CertificateFactory cf = getCertificateFactory();
                    X509CRL crl = (X509CRL)cf.generateCRL(is);
                    crls.add(crl);
                } catch (Exception e) {
                    if (DO_DEBUG) {
                        LOG.debug(e.getMessage(), e);
                    }
                    throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "ioError00", e);
                } finally {
                    if (is != null) {
                        is.close();
                    }
                }
            }
            try {
                if (provider == null || provider.length() == 0) {
                    crlCertStore =
                            CertStore.getInstance(
                                    "Collection",
                                    new CollectionCertStoreParameters(crls)
                            );

                } else {
                    crlCertStore =
                            CertStore.getInstance(
                                    "Collection",
                                    new CollectionCertStoreParameters(crls),
                                    provider
                            );
                }
            } catch (Exception e) {
                if (DO_DEBUG) {
                    LOG.debug(e.getMessage(), e);
                }
                throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "ioError00", e);
            }
            if (DO_DEBUG) {
                LOG.debug(
                        "The CRL " + crlLocations + " has been loaded"
                );
            }

        }
    }


    /**
     * Load a KeyStore object as an InputStream, using the ClassLoader and location arguments
     */
    public static InputStream loadInputStream(ClassLoader loader, String location)
            throws WSSecurityException, IOException {
        InputStream is = null;
        if (location != null) {
            java.net.URL url = Loader.getResource(loader, location);
            if (url != null) {
                is = url.openStream();
            }

            //
            // If we don't find it, then look on the file system.
            //
            if (is == null) {
                try {
                    is = new FileInputStream(location);
                } catch (Exception e) {
                    if (DO_DEBUG) {
                        LOG.debug(e.getMessage(), e);
                    }
                    throw new WSSecurityException(
                            WSSecurityException.ErrorCode.FAILURE, "proxyNotFound", e, location
                    );
                }
            }
        }
        return is;
    }


    /**
     * Loads the keystore from an <code>InputStream </code>.
     * <p/>
     *
     * @param input <code>InputStream</code> to read from
     * @throws WSSecurityException
     */
    public KeyStore load(InputStream input, String storepass, String provider, String type)
            throws WSSecurityException {
        KeyStore ks = null;

        try {
            if (provider == null || provider.length() == 0) {
                ks = KeyStore.getInstance(type);
            } else {
                ks = KeyStore.getInstance(type, provider);
            }

            ks.load(input, storepass == null || storepass.length() == 0
                    ? new char[0] : storepass.toCharArray());
        } catch (IOException e) {
            if (DO_DEBUG) {
                LOG.debug(e.getMessage(), e);
            }
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "ioError00", e);
        } catch (GeneralSecurityException e) {
            if (DO_DEBUG) {
                LOG.debug(e.getMessage(), e);
            }
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "secError00", e);
        } catch (Exception e) {
            if (DO_DEBUG) {
                LOG.debug(e.getMessage(), e);
            }
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "error00", e);
        }
        return ks;
    }

    //
    // Accessor methods
    //

    /**
     * Gets the Keystore that was loaded
     *
     * @return the Keystore
     */
    public KeyStore getKeyStore() {
        return keystore;
    }

    /**
     * Set the Keystore on this Crypto instance
     *
     * @param keyStore the Keystore to set
     */
    public void setKeyStore(KeyStore keyStore) {
        keystore = keyStore;
    }

    /**
     * Gets the trust store that was loaded by the underlying implementation
     *
     * @return the trust store
     */
    public KeyStore getTrustStore() {
        return truststore;
    }

    /**
     * Set the trust store on this Crypto instance
     *
     * @param trustStore the trust store to set
     */
    public void setTrustStore(KeyStore trustStore) {
        truststore = trustStore;
    }

    /**
     * Set the CertStore from which to obtain a list of CRLs for Certificate Revocation
     * checking.
     * @param crlCertStore the CertStore from which to obtain a list of CRLs for Certificate 
     * Revocation checking.
     */
    public void setCRLCertStore(CertStore crlCertStore) {
        this.crlCertStore = crlCertStore;
    }

    /**
     * Get the CertStore from which to obtain a list of CRLs for Certificate Revocation
     * checking.
     * @return the CertStore from which to obtain a list of CRLs for Certificate 
     * Revocation checking.
     */
    public CertStore getCRLCertStore() {
        return crlCertStore;
    }

    /**
     * Singleton certificate factory for this Crypto instance.
     * <p/>
     *
     * @return Returns a <code>CertificateFactory</code> to construct
     *         X509 certificates
     * @throws WSSecurityException
     */
    @Override
    public CertificateFactory getCertificateFactory() throws WSSecurityException {
        String provider = getCryptoProvider();
        String keyStoreProvider = null;
        if (keystore != null) {
            keyStoreProvider = keystore.getProvider().getName();
        }

        //Try to find a CertificateFactory that generates certs that are fully
        //compatible with the certs in the KeyStore  (Sun -> Sun, BC -> BC, etc...)
        CertificateFactory factory = null;
        if (provider != null) {
            factory = certFactMap.get(provider);
        } else if (keyStoreProvider != null) {
            factory =
                    certFactMap.get(mapKeystoreProviderToCertProvider(keyStoreProvider));
            if (factory == null) {
                factory = certFactMap.get(keyStoreProvider);
            }
        } else {
            factory = certFactMap.get("DEFAULT");
        }
        if (factory == null) {
            try {
                if (provider == null || provider.length() == 0) {
                    if (keyStoreProvider != null && keyStoreProvider.length() != 0) {
                        try {
                            factory =
                                    CertificateFactory.getInstance(
                                            "X.509", mapKeystoreProviderToCertProvider(keyStoreProvider)
                                    );
                            certFactMap.put(keyStoreProvider, factory);
                            certFactMap.put(
                                    mapKeystoreProviderToCertProvider(keyStoreProvider), factory
                            );
                        } catch (Exception ex) {
                            LOG.debug(ex.getMessage(), ex);
                            //Ignore, we'll just use the default since they didn't specify one.
                            //Hopefully that will work for them.
                        }
                    }
                    if (factory == null) {
                        factory = CertificateFactory.getInstance("X.509");
                        certFactMap.put("DEFAULT", factory);
                    }
                } else {
                    factory = CertificateFactory.getInstance("X.509", provider);
                    certFactMap.put(provider, factory);
                }
                certFactMap.put(factory.getProvider().getName(), factory);
            } catch (CertificateException e) {
                throw new WSSecurityException(
                        WSSecurityException.ErrorCode.SECURITY_TOKEN_UNAVAILABLE, "unsupportedCertType", e
                );
            } catch (NoSuchProviderException e) {
                throw new WSSecurityException(
                        WSSecurityException.ErrorCode.SECURITY_TOKEN_UNAVAILABLE, "noSecProvider", e
                );
            }
        }
        return factory;
    }

    private String mapKeystoreProviderToCertProvider(String s) {
        if ("SunJSSE".equals(s)) {
            return "SUN";
        }
        return s;
    }

    /**
     * Retrieves the identifier name of the default certificate. This should be the certificate 
     * that is used for signature and encryption. This identifier corresponds to the certificate 
     * that should be used whenever KeyInfo is not present in a signed or an encrypted 
     * message. May return null. The identifier is implementation specific, e.g. it could be the
     * KeyStore alias.
     *
     * @return name of the default X509 certificate.
     */
    @Override
    public String getDefaultX509Identifier() throws WSSecurityException {
        if (defaultAlias != null) {
            return defaultAlias;
        }

        if (keystore != null) {
            try {
                Enumeration<String> as = keystore.aliases();
                if (as.hasMoreElements()) {
                    String alias = as.nextElement();
                    if (!as.hasMoreElements()) {
                        defaultAlias = alias;
                        return alias;
                    }
                }
            } catch (KeyStoreException ex) {
                throw new WSSecurityException(
                        WSSecurityException.ErrorCode.FAILURE, "keystore", ex
                );
            }
        }
        return null;
    }

    //
    // Keystore-specific Crypto functionality methods
    //

    /**
     * Get an X509Certificate (chain) corresponding to the CryptoType argument. The supported
     * types are as follows:
     *
     * TYPE.ISSUER_SERIAL - A certificate (chain) is located by the issuer name and serial number
     * TYPE.THUMBPRINT_SHA1 - A certificate (chain) is located by the SHA1 of the (root) cert
     * TYPE.SKI_BYTES - A certificate (chain) is located by the SKI bytes of the (root) cert
     * TYPE.SUBJECT_DN - A certificate (chain) is located by the Subject DN of the (root) cert
     * TYPE.ALIAS - A certificate (chain) is located by an alias, which for this implementation
     * means an alias of the keystore or truststore.
     */
    public X509Certificate[] getX509Certificates(CryptoType cryptoType) throws WSSecurityException {
        if (cryptoType == null) {
            return null;
        }
        CryptoType.TYPE type = cryptoType.getType();
        X509Certificate[] certs = null;
        switch (type) {
            case ISSUER_SERIAL: {
                certs = getX509Certificates(cryptoType.getIssuer(), cryptoType.getSerial());
                break;
            }
            case THUMBPRINT_SHA1: {
                certs = getX509Certificates(cryptoType.getBytes());
                break;
            }
            case SKI_BYTES: {
                certs = getX509CertificatesSKI(cryptoType.getBytes());
                break;
            }
            case SUBJECT_DN: {
                certs = getX509CertificatesSubjectDN(cryptoType.getSubjectDN());
                break;
            }
            case ALIAS: {
                certs = getX509Certificates(cryptoType.getAlias());
                break;
            }
            case ENDPOINT: {
                break;
            }
        }
        return certs;
    }

    /**
     * Get the implementation-specific identifier corresponding to the cert parameter. In this 
     * case, the identifier corresponds to a KeyStore alias.
     * @param cert The X509Certificate for which to search for an identifier
     * @return the identifier corresponding to the cert parameter
     * @throws WSSecurityException
     */
    public String getX509Identifier(X509Certificate cert) throws WSSecurityException {
        String identifier = null;

        if (keystore != null) {
            identifier = getIdentifier(cert, keystore);
        }

        if (identifier == null && truststore != null) {
            identifier = getIdentifier(cert, truststore);
        }

        return identifier;
    }

    /**
     * Gets the private key corresponding to the certificate.
     *
     * @param certificate The X509Certificate corresponding to the private key
     * @param callbackHandler The callbackHandler needed to get the password
     * @return The private key
     */
    public PrivateKey getPrivateKey(
            X509Certificate certificate,
            CallbackHandler callbackHandler
    ) throws WSSecurityException {
        if (keystore == null) {
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty", "The keystore is null");
        }
        if (callbackHandler == null) {
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty", "The CallbackHandler is null");
        }

        String identifier = getIdentifier(certificate, keystore);
        try {
            if (identifier == null || !keystore.isKeyEntry(identifier)) {
                String msg = "Cannot find key for alias: [" + identifier + "]";
                String logMsg = createKeyStoreErrorMessage(keystore);
                LOG.error(msg + logMsg);
                throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty", msg);
            }
            String password = getPassword(identifier, callbackHandler);
            if (password == null && privatePasswordSet) {
                password = properties.getProperty(PREFIX + KEYSTORE_PRIVATE_PASSWORD);
                if (password == null) {
                    password = properties.getProperty(OLD_PREFIX + KEYSTORE_PRIVATE_PASSWORD);
                }
                if (password != null) {
                    password = password.trim();
                    password = decryptPassword(password, passwordEncryptor);
                }
            }
            Key keyTmp = keystore.getKey(identifier, password == null
                    ? new char[]{} : password.toCharArray());
            if (!(keyTmp instanceof PrivateKey)) {
                String msg = "Key is not a private key, alias: [" + identifier + "]";
                String logMsg = createKeyStoreErrorMessage(keystore);
                LOG.error(msg + logMsg);
                throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty", msg);
            }
            return (PrivateKey) keyTmp;
        } catch (KeyStoreException ex) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "noPrivateKey", ex, ex.getMessage()
            );
        } catch (UnrecoverableKeyException ex) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "noPrivateKey", ex, ex.getMessage()
            );
        } catch (NoSuchAlgorithmException ex) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "noPrivateKey", ex, ex.getMessage()
            );
        }
    }

    /**
     * Gets the private key corresponding to the identifier.
     *
     * @param identifier The implementation-specific identifier corresponding to the key
     * @param password The password needed to get the key
     * @return The private key
     */
    public PrivateKey getPrivateKey(
            String identifier,
            String password
    ) throws WSSecurityException {
        if (keystore == null) {
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty", "The keystore is null");
        }
        try {
            if (identifier == null || !keystore.isKeyEntry(identifier)) {
                String msg = "Cannot find key for alias: [" + identifier + "]";
                String logMsg = createKeyStoreErrorMessage(keystore);
                LOG.error(msg + logMsg);
                throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty", msg);
            }
            if (password == null && privatePasswordSet) {
                password = properties.getProperty(PREFIX + KEYSTORE_PRIVATE_PASSWORD);
                if (password == null) {
                    password = properties.getProperty(OLD_PREFIX + KEYSTORE_PRIVATE_PASSWORD);
                }
                if (password != null) {
                    password = password.trim();
                }
            }
            Key keyTmp = keystore.getKey(identifier, password == null
                    ? new char[]{} : password.toCharArray());
            if (!(keyTmp instanceof PrivateKey)) {
                String msg = "Key is not a private key, alias: [" + identifier + "]";
                String logMsg = createKeyStoreErrorMessage(keystore);
                LOG.error(msg + logMsg);
                throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty", msg);
            }
            return (PrivateKey) keyTmp;
        } catch (KeyStoreException ex) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "noPrivateKey", ex, ex.getMessage()
            );
        } catch (UnrecoverableKeyException ex) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "noPrivateKey", ex, ex.getMessage()
            );
        } catch (NoSuchAlgorithmException ex) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "noPrivateKey", ex, ex.getMessage()
            );
        }
    }

    /**
     * Evaluate whether a given certificate chain should be trusted.
     *
     * @param certs Certificate chain to validate
     * @param enableRevocation whether to enable CRL verification or not
     * @param subjectCertConstraints A set of constraints on the Subject DN of the certificates
     *
     * @throws WSSecurityException if the certificate chain is invalid
     */
    public void verifyTrust(
            X509Certificate[] certs,
            boolean enableRevocation,
            Collection<Pattern> subjectCertConstraints
    ) throws WSSecurityException {
        //
        // FIRST step - Search the keystore for the transmitted certificate
        //
        if (certs.length == 1 && !enableRevocation) {
            String issuerString = certs[0].getIssuerX500Principal().getName();
            BigInteger issuerSerial = certs[0].getSerialNumber();

            CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ISSUER_SERIAL);
            cryptoType.setIssuerSerial(issuerString, issuerSerial);
            X509Certificate[] foundCerts = getX509Certificates(cryptoType);

            //
            // If a certificate has been found, the certificates must be compared
            // to ensure against phony DNs (compare encoded form including signature)
            //
            if (foundCerts != null && foundCerts[0] != null && foundCerts[0].equals(certs[0])) {
                try {
                    certs[0].checkValidity();
                } catch (CertificateExpiredException e) {
                    throw new WSSecurityException(
                            WSSecurityException.ErrorCode.FAILED_CHECK, "invalidCert", e
                    );
                } catch (CertificateNotYetValidException e) {
                    throw new WSSecurityException(
                            WSSecurityException.ErrorCode.FAILED_CHECK, "invalidCert", e
                    );
                }
                if (LOG.isDebugEnabled()) {
                    LOG.debug(
                            "Direct trust for certificate with " + certs[0].getSubjectX500Principal().getName()
                    );
                }
                return;
            }
        }

        //
        // SECOND step - Search for the issuer cert (chain) of the transmitted certificate in the 
        // keystore or the truststore
        //
        X509Certificate[] x509certs = certs;
        String issuerString = certs[0].getIssuerX500Principal().getName();
        if (certs.length == 1) {
            CryptoType cryptoType = new CryptoType(CryptoType.TYPE.SUBJECT_DN);
            cryptoType.setSubjectDN(issuerString);
            X509Certificate[] foundCerts = getX509Certificates(cryptoType);

            // If the certs have not been found, the issuer is not in the keystore/truststore
            // As a direct result, do not trust the transmitted certificate
            if (foundCerts == null || foundCerts.length < 1) {
                String subjectString = certs[0].getSubjectX500Principal().getName();
                if (LOG.isDebugEnabled()) {
                    LOG.debug(
                            "No certs found in keystore for issuer " + issuerString
                                    + " of certificate for " + subjectString
                    );
                }
                throw new WSSecurityException(
                        WSSecurityException.ErrorCode.FAILURE, "certpath", "No trusted certs found"
                );
            }

            //
            // Form a certificate chain from the transmitted certificate
            // and the certificate(s) of the issuer from the keystore/truststore
            //
            x509certs = new X509Certificate[foundCerts.length + 1];
            x509certs[0] = certs[0];
            System.arraycopy(foundCerts, 0, x509certs, 1, foundCerts.length);
        }

        //
        // THIRD step
        // Check the certificate trust path for the issuer cert chain
        //
        if (LOG.isDebugEnabled()) {
            LOG.debug(
                    "Preparing to validate certificate path for issuer " + issuerString
            );
        }

        try {
            // Generate cert path
            List<X509Certificate> certList = Arrays.asList(x509certs);
            CertPath path = getCertificateFactory().generateCertPath(certList);

            Set<TrustAnchor> set = new HashSet<TrustAnchor>();
            if (truststore != null) {
                Enumeration<String> truststoreAliases = truststore.aliases();
                while (truststoreAliases.hasMoreElements()) {
                    String alias = truststoreAliases.nextElement();
                    X509Certificate cert =
                            (X509Certificate) truststore.getCertificate(alias);
                    if (cert != null) {
                        TrustAnchor anchor =
                                new TrustAnchor(cert, cert.getExtensionValue(NAME_CONSTRAINTS_OID));
                        set.add(anchor);
                    }
                }
            }

            //
            // Add certificates from the keystore - only if there is no TrustStore, apart from
            // the case that the truststore is the JDK CA certs. This behaviour is preserved
            // for backwards compatibility reasons
            //
            if (keystore != null && (truststore == null || loadCACerts)) {
                Enumeration<String> aliases = keystore.aliases();
                while (aliases.hasMoreElements()) {
                    String alias = aliases.nextElement();
                    X509Certificate cert =
                            (X509Certificate) keystore.getCertificate(alias);
                    if (cert != null) {
                        TrustAnchor anchor =
                                new TrustAnchor(cert, cert.getExtensionValue(NAME_CONSTRAINTS_OID));
                        set.add(anchor);
                    }
                }
            }

            // Verify the trust path using the above settings
            String provider = getCryptoProvider();
            CertPathValidator validator = null;
            if (provider == null || provider.length() == 0) {
                validator = CertPathValidator.getInstance("PKIX");
            } else {
                validator = CertPathValidator.getInstance("PKIX", provider);
            }

            PKIXParameters param = createPKIXParameters(set, enableRevocation);
            validator.validate(path, param);
        } catch (NoSuchProviderException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "certpath", e
            );
        } catch (NoSuchAlgorithmException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE,
                    "certpath", e, e.getMessage()
            );
        } catch (CertificateException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "certpath", e
            );
        } catch (InvalidAlgorithmParameterException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "certpath", e
            );
        } catch (java.security.cert.CertPathValidatorException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILED_AUTHENTICATION, "certpath", e
            );
        } catch (KeyStoreException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "certpath", e
            );
        } catch (NullPointerException e) {
            // NPE thrown by JDK 1.7 for one of the test cases
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "certpath", e
            );
        }

        // Finally check Cert Constraints
        if (!matches(certs[0], subjectCertConstraints)) {
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
        }
    }

    // Separated out to allow subclasses to override it
    protected PKIXParameters createPKIXParameters(
            Set<TrustAnchor> trustAnchors, boolean enableRevocation
    ) throws InvalidAlgorithmParameterException {
        PKIXParameters param = new PKIXParameters(trustAnchors);
        param.setRevocationEnabled(enableRevocation);
        if (enableRevocation && crlCertStore != null) {
            param.addCertStore(crlCertStore);
        }

        return param;
    }

    /**
     * Evaluate whether a given public key should be trusted.
     *
     * @param publicKey The PublicKey to be evaluated
     * @throws WSSecurityException if the PublicKey is invalid
     */
    public void verifyTrust(PublicKey publicKey) throws WSSecurityException {
        //
        // If the public key is null, do not trust the signature
        //
        if (publicKey == null) {
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
        }

        //
        // Search the keystore for the transmitted public key (direct trust). If not found
        // then search the truststore for the transmitted public key (direct trust)
        //
        if (!findPublicKeyInKeyStore(publicKey, keystore)
                && !findPublicKeyInKeyStore(publicKey, truststore)) {
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
        }
    }

    /**
     * Get an X509 Certificate (chain) according to a given serial number and issuer string.
     *
     * @param issuer The Issuer String
     * @param serialNumber The serial number of the certificate
     * @return an X509 Certificate (chain) corresponding to the found certificate(s)
     * @throws WSSecurityException
     */
    private X509Certificate[] getX509Certificates(
            String issuer,
            BigInteger serialNumber
    ) throws WSSecurityException {
        //
        // Convert the subject DN to a java X500Principal object first. This is to ensure
        // interop with a DN constructed from .NET, where e.g. it uses "S" instead of "ST".
        // Then convert it to a BouncyCastle X509Name, which will order the attributes of
        // the DN in a particular way (see WSS-168). If the conversion to an X500Principal
        // object fails (e.g. if the DN contains "E" instead of "EMAILADDRESS"), then fall
        // back on a direct conversion to a BC X509Name
        //
        Object issuerName = null;
        try {
            X500Principal issuerRDN = new X500Principal(issuer);
            issuerName = createBCX509Name(issuerRDN.getName());
        } catch (IllegalArgumentException ex) {
            issuerName = createBCX509Name(issuer);
        }
        Certificate[] certs = null;
        if (keystore != null) {
            certs = getCertificates(issuerName, serialNumber, keystore);
        }

        //If we can't find the issuer in the keystore then look at the truststore
        if ((certs == null || certs.length == 0) && truststore != null) {
            certs = getCertificates(issuerName, serialNumber, truststore);
        }

        if (certs == null || certs.length == 0) {
            return null;
        }

        X509Certificate[] x509certs = new X509Certificate[certs.length];
        for (int i = 0; i < certs.length; i++) {
            x509certs[i] = (X509Certificate) certs[i];
        }
        return x509certs;
    }

    /**
     * Get an X509 Certificate (chain) of the X500Principal argument in the supplied KeyStore 
     * @param issuerRDN either an X500Principal or a BouncyCastle X509Name instance.
     * @param store The KeyStore
     * @return an X509 Certificate (chain)
     * @throws WSSecurityException
     */
    private Certificate[] getCertificates(
            Object issuerRDN,
            BigInteger serialNumber,
            KeyStore store
    ) throws WSSecurityException {
        try {
            for (Enumeration<String> e = store.aliases(); e.hasMoreElements();) {
                String alias = e.nextElement();
                Certificate cert = null;
                Certificate[] certs = store.getCertificateChain(alias);
                if (certs == null || certs.length == 0) {
                    // no cert chain, so lets check if getCertificate gives us a result.
                    cert = store.getCertificate(alias);
                    if (cert == null) {
                        continue;
                    }
                    certs = new Certificate[]{cert};
                } else {
                    cert = certs[0];
                }
                if (cert instanceof X509Certificate) {
                    X509Certificate x509cert = (X509Certificate) cert;
                    if (x509cert.getSerialNumber().compareTo(serialNumber) == 0) {
                        Object certName =
                                createBCX509Name(x509cert.getIssuerX500Principal().getName());
                        if (certName.equals(issuerRDN)) {
                            return certs;
                        }
                    }
                }
            }
        } catch (KeyStoreException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "keystore", e
            );
        }
        return new Certificate[]{};
    }

    /**
     * Get an X509 Certificate (chain) according to a given Thumbprint.
     *
     * @param thumbprint The SHA1 thumbprint info bytes
     * @return the X509 Certificate (chain) that was found (can be null)
     * @throws WSSecurityException if problems during keystore handling or wrong certificate
     */
    private X509Certificate[] getX509Certificates(byte[] thumbprint) throws WSSecurityException {
        MessageDigest sha = null;

        try {
            sha = MessageDigest.getInstance("SHA1");
        } catch (NoSuchAlgorithmException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "decoding.general", e
            );
        }
        Certificate[] certs = null;
        if (keystore != null) {
            certs = getCertificates(thumbprint, keystore, sha);
        }

        //If we can't find the issuer in the keystore then look at the truststore
        if ((certs == null || certs.length == 0) && truststore != null) {
            certs = getCertificates(thumbprint, truststore, sha);
        }

        if (certs == null || certs.length == 0) {
            return null;
        }

        X509Certificate[] x509certs = new X509Certificate[certs.length];
        for (int i = 0; i < certs.length; i++) {
            x509certs[i] = (X509Certificate) certs[i];
        }
        return x509certs;
    }

    /**
     * Get an X509 Certificate (chain) of the X500Principal argument in the supplied KeyStore 
     * @param thumbprint
     * @param store The KeyStore
     * @return an X509 Certificate (chain)
     * @throws WSSecurityException
     */
    private Certificate[] getCertificates(
            byte[] thumbprint,
            KeyStore store,
            MessageDigest sha
    ) throws WSSecurityException {
        try {
            for (Enumeration<String> e = store.aliases(); e.hasMoreElements();) {
                String alias = e.nextElement();
                Certificate cert = null;
                Certificate[] certs = store.getCertificateChain(alias);
                if (certs == null || certs.length == 0) {
                    // no cert chain, so lets check if getCertificate gives us a result.
                    cert = store.getCertificate(alias);
                    if (cert == null) {
                        continue;
                    }
                    certs = new Certificate[]{cert};
                } else {
                    cert = certs[0];
                }
                if (cert instanceof X509Certificate) {
                    X509Certificate x509cert = (X509Certificate) cert;
                    try {
                        sha.update(x509cert.getEncoded());
                    } catch (CertificateEncodingException ex) {
                        throw new WSSecurityException(
                                WSSecurityException.ErrorCode.SECURITY_TOKEN_UNAVAILABLE, "encodeError",
                                ex
                        );
                    }
                    byte[] data = sha.digest();

                    if (Arrays.equals(data, thumbprint)) {
                        return certs;
                    }
                }
            }
        } catch (KeyStoreException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "keystore", e
            );
        }
        return new Certificate[]{};
    }

    /**
     * Get an X509 Certificate (chain) according to a given SubjectKeyIdentifier.
     *
     * @param skiBytes The SKI bytes
     * @return the X509 certificate (chain) that was found (can be null)
     */
    private X509Certificate[] getX509CertificatesSKI(byte[] skiBytes) throws WSSecurityException {
        Certificate[] certs = null;
        if (keystore != null) {
            certs = getCertificates(skiBytes, keystore);
        }

        //If we can't find the issuer in the keystore then look at the truststore
        if ((certs == null || certs.length == 0) && truststore != null) {
            certs = getCertificates(skiBytes, truststore);
        }

        if (certs == null || certs.length == 0) {
            return null;
        }

        X509Certificate[] x509certs = new X509Certificate[certs.length];
        for (int i = 0; i < certs.length; i++) {
            x509certs[i] = (X509Certificate) certs[i];
        }
        return x509certs;
    }

    /**
     * Get an X509 Certificate (chain) of the X500Principal argument in the supplied KeyStore 
     * @param skiBytes
     * @param store The KeyStore
     * @return an X509 Certificate (chain)
     * @throws WSSecurityException
     */
    private Certificate[] getCertificates(
            byte[] skiBytes,
            KeyStore store
    ) throws WSSecurityException {
        try {
            for (Enumeration<String> e = store.aliases(); e.hasMoreElements();) {
                String alias = e.nextElement();
                Certificate cert = null;
                Certificate[] certs = store.getCertificateChain(alias);
                if (certs == null || certs.length == 0) {
                    // no cert chain, so lets check if getCertificate gives us a result.
                    cert = store.getCertificate(alias);
                    if (cert == null) {
                        continue;
                    }
                    certs = new Certificate[]{cert};
                } else {
                    cert = certs[0];
                }
                if (cert instanceof X509Certificate) {
                    X509Certificate x509cert = (X509Certificate) cert;
                    byte[] data = getSKIBytesFromCert(x509cert);
                    if (data.length == skiBytes.length && Arrays.equals(data, skiBytes)) {
                        return certs;
                    }
                }
            }
        } catch (KeyStoreException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "keystore", e
            );
        }
        return new Certificate[]{};
    }

    /**
     * Get an X509 Certificate (chain) according to a given DN of the subject of the certificate
     *
     * @param subjectDN The DN of subject to look for
     * @return An X509 Certificate (chain) with the same DN as given in the parameters
     * @throws WSSecurityException
     */
    private X509Certificate[] getX509CertificatesSubjectDN(String subjectDN) throws WSSecurityException {
        //
        // Convert the subject DN to a java X500Principal object first. This is to ensure
        // interop with a DN constructed from .NET, where e.g. it uses "S" instead of "ST".
        // Then convert it to a BouncyCastle X509Name, which will order the attributes of
        // the DN in a particular way (see WSS-168). If the conversion to an X500Principal
        // object fails (e.g. if the DN contains "E" instead of "EMAILADDRESS"), then fall
        // back on a direct conversion to a BC X509Name
        //
        Object subject;
        try {
            X500Principal subjectRDN = new X500Principal(subjectDN);
            subject = createBCX509Name(subjectRDN.getName());
        } catch (IllegalArgumentException ex) {
            subject = createBCX509Name(subjectDN);
        }

        Certificate[] certs = null;
        if (keystore != null) {
            certs = getCertificates(subject, keystore);
        }

        //If we can't find the issuer in the keystore then look at the truststore
        if ((certs == null || certs.length == 0) && truststore != null) {
            certs = getCertificates(subject, truststore);
        }

        if (certs == null || certs.length == 0) {
            return null;
        }

        X509Certificate[] x509certs = new X509Certificate[certs.length];
        for (int i = 0; i < certs.length; i++) {
            x509certs[i] = (X509Certificate) certs[i];
        }
        return x509certs;
    }

    /**
     * Get an X509 Certificate (chain) that correspond to the identifier. For this implementation,
     * the identifier corresponds to the KeyStore alias.
     *
     * @param identifier The identifier that corresponds to the returned certs
     * @return an X509 Certificate (chain) that corresponds to the identifier
     */
    private X509Certificate[] getX509Certificates(String identifier) throws WSSecurityException {
        Certificate[] certs = null;
        try {
            if (keystore != null) {
                // There's a chance that there can only be a set of trust stores
                certs = keystore.getCertificateChain(identifier);
                if (certs == null || certs.length == 0) {
                    // no cert chain, so lets check if getCertificate gives us a result.
                    Certificate cert = keystore.getCertificate(identifier);
                    if (cert != null) {
                        certs = new Certificate[]{cert};
                    }
                }
            }

            if (certs == null && truststore != null) {
                // Now look into the trust stores
                certs = truststore.getCertificateChain(identifier);
                if (certs == null) {
                    Certificate cert = truststore.getCertificate(identifier);
                    if (cert != null) {
                        certs = new Certificate[]{cert};
                    }
                }
            }

            if (certs == null) {
                return null;
            }
        } catch (KeyStoreException e) {
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "keystore", e);
        }

        X509Certificate[] x509certs = new X509Certificate[certs.length];
        for (int i = 0; i < certs.length; i++) {
            x509certs[i] = (X509Certificate) certs[i];
        }
        return x509certs;
    }

    /**
     * Find the Public Key in a keystore. 
     */
    private boolean findPublicKeyInKeyStore(PublicKey publicKey, KeyStore keyStoreToSearch) {
        if (keyStoreToSearch == null) {
            return false;
        }
        try {
            for (Enumeration<String> e = keyStoreToSearch.aliases(); e.hasMoreElements();) {
                String alias = e.nextElement();
                Certificate[] certs = keyStoreToSearch.getCertificateChain(alias);
                Certificate cert;
                if (certs == null || certs.length == 0) {
                    // no cert chain, so lets check if getCertificate gives us a result.
                    cert = keyStoreToSearch.getCertificate(alias);
                    if (cert == null) {
                        continue;
                    }
                } else {
                    cert = certs[0];
                }
                if (!(cert instanceof X509Certificate)) {
                    continue;
                }
                X509Certificate x509cert = (X509Certificate) cert;
                if (publicKey.equals(x509cert.getPublicKey())) {
                    return true;
                }
            }
        } catch (KeyStoreException e) {
            return false;
        }
        return false;
    }

    /**
     * Get an X509 Certificate (chain) of the X500Principal argument in the supplied KeyStore 
     * @param subjectRDN either an X500Principal or a BouncyCastle X509Name instance.
     * @param store The KeyStore
     * @return an X509 Certificate (chain)
     * @throws WSSecurityException
     */
    private Certificate[] getCertificates(Object subjectRDN, KeyStore store)
            throws WSSecurityException {
        try {
            for (Enumeration<String> e = store.aliases(); e.hasMoreElements();) {
                String alias = e.nextElement();
                Certificate cert = null;
                Certificate[] certs = store.getCertificateChain(alias);
                if (certs == null || certs.length == 0) {
                    // no cert chain, so lets check if getCertificate gives us a result.
                    cert = store.getCertificate(alias);
                    if (cert == null) {
                        continue;
                    }
                    certs = new Certificate[]{cert};
                } else {
                    cert = certs[0];
                }
                if (cert instanceof X509Certificate) {
                    X500Principal foundRDN = ((X509Certificate) cert).getSubjectX500Principal();
                    Object certName = createBCX509Name(foundRDN.getName());

                    if (subjectRDN.equals(certName)) {
                        return certs;
                    }
                }
            }
        } catch (KeyStoreException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "keystore", e
            );
        }
        return new Certificate[]{};
    }

    private static String createKeyStoreErrorMessage(KeyStore keystore) throws KeyStoreException {
        Enumeration<String> aliases = keystore.aliases();
        StringBuilder sb = new StringBuilder(keystore.size() * 7);
        boolean firstAlias = true;
        while (aliases.hasMoreElements()) {
            if (!firstAlias) {
                sb.append(", ");
            }
            sb.append(aliases.nextElement());
            firstAlias = false;
        }
        String msg = " in keystore of type [" + keystore.getType()
                + "] from provider [" + keystore.getProvider()
                + "] with size [" + keystore.size() + "] and aliases: {"
                + sb.toString() + "}";
        return msg;
    }

    /**
     * Get an implementation-specific identifier that corresponds to the X509Certificate. In
     * this case, the identifier is the KeyStore alias.
     * @param cert The X509Certificate corresponding to the returned identifier
     * @param store The KeyStore to search
     * @return An implementation-specific identifier that corresponds to the X509Certificate
     */
    private String getIdentifier(X509Certificate cert, KeyStore store)
            throws WSSecurityException {
        try {
            for (Enumeration<String> e = store.aliases(); e.hasMoreElements();) {
                String alias = e.nextElement();

                Certificate[] certs = store.getCertificateChain(alias);
                Certificate retrievedCert = null;
                if (certs == null || certs.length == 0) {
                    // no cert chain, so lets check if getCertificate gives us a  result.
                    retrievedCert = store.getCertificate(alias);
                    if (retrievedCert == null) {
                        continue;
                    }
                } else {
                    retrievedCert = certs[0];
                }
                if (!(retrievedCert instanceof X509Certificate)) {
                    continue;
                }
                if (retrievedCert.equals(cert)) {
                    return alias;
                }
            }
        } catch (KeyStoreException e) {
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "keystore", e);
        }
        return null;
    }

    /**
     * Get a password from the CallbackHandler
     * @param identifier The identifier to give to the Callback
     * @param cb The CallbackHandler
     * @return The password retrieved from the CallbackHandler
     * @throws WSSecurityException
     */
    private String getPassword(
            String identifier,
            CallbackHandler cb
    ) throws WSSecurityException {
        WSPasswordCallback pwCb =
                new WSPasswordCallback(identifier, WSPasswordCallback.DECRYPT);
        try {
            Callback[] callbacks = new Callback[]{pwCb};
            cb.handle(callbacks);
        } catch (IOException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE,
                    "noPassword", e, identifier
            );
        } catch (UnsupportedCallbackException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE,
                    "noPassword", e, identifier
            );
        }

        return pwCb.getPassword();
    }

    protected String decryptPassword(String password, PasswordEncryptor passwordEncryptor) {
        if (password.startsWith(ENCRYPTED_PASSWORD_PREFIX)
                && password.endsWith(ENCRYPTED_PASSWORD_SUFFIX)) {
            if (passwordEncryptor == null) {
                String error =
                        "The Crypto properties has an encrypted password, but no PasswordEncryptor is configured!";
                LOG.debug(error);
                return password;
            }
            String substring = password.substring(ENCRYPTED_PASSWORD_PREFIX.length(),
                    password.length() - 1);
            return passwordEncryptor.decrypt(substring);
        }

        return password;
    }

    public void setPasswordEncryptor(PasswordEncryptor passwordEncryptor) {
        this.passwordEncryptor = passwordEncryptor;
    }
}

Reply via email to