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

org.bouncycastle.jsse.provider.BouncyCastleJsseProvider Maven / Gradle / Ivy

package org.bouncycastle.jsse.provider;

import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider;
import org.bouncycastle.util.Strings;

public class BouncyCastleJsseProvider
    extends Provider
{
    private static String info = "Bouncy Castle JSSE Provider Beta Version";

    public static final String PROVIDER_NAME = "BCJSSE";

    private static final double version = 0.9;

    private Map serviceMap = new HashMap();
    private Map creatorMap = new HashMap();

    private boolean isInFipsMode;

    public BouncyCastleJsseProvider()
    {
        super(PROVIDER_NAME, version, info);

        configure(false, new JcaTlsCryptoProvider());
    }

    public BouncyCastleJsseProvider(Provider provider)
    {
        this(false, provider);
    }

    public BouncyCastleJsseProvider(boolean isInFipsMode, Provider provider)
    {
        super(PROVIDER_NAME, version, info);

        configure(isInFipsMode, new JcaTlsCryptoProvider().setProvider(provider));
    }

    public BouncyCastleJsseProvider(String config)
    {
        super(PROVIDER_NAME, version, info);

        boolean isFips = false;

        try
        {
            if (config.indexOf(':') > 0)
            {
                isFips = config.substring(0, config.indexOf(':')).trim().equalsIgnoreCase("fips");

                String cryptoName = config.substring(config.indexOf(':') + 1).trim();

                configure(isFips, createCryptoProvider(cryptoName));
            }
            else
            {
                configure(isFips, createCryptoProvider(config.trim()));
            }
        }
        catch (GeneralSecurityException e)
        {
            throw new IllegalArgumentException("unable to set up TlsCrypto: " + e.getMessage(), e);
        }
    }

    public BouncyCastleJsseProvider(boolean fipsMode, JcaTlsCryptoProvider tlsCryptoProvider)
    {
        super(PROVIDER_NAME, version, info);

        configure(fipsMode, tlsCryptoProvider);
    }
    
    private JcaTlsCryptoProvider createCryptoProvider(String cryptoName)
        throws GeneralSecurityException
    {
        if (cryptoName.equalsIgnoreCase("default"))
        {
            return new JcaTlsCryptoProvider();
        }
        else
        {
            Provider provider = Security.getProvider(cryptoName);

            if (provider != null)
            {
                return new JcaTlsCryptoProvider().setProvider(provider);
            }
            else
            {
                try
                {
                    Class cryptoProviderClass = Class.forName(cryptoName);

                    // the TlsCryptoProvider/Provider class named requires a no-args constructor
                    Object o = cryptoProviderClass.newInstance();
                    if (o instanceof JcaTlsCryptoProvider)
                    {
                        return (JcaTlsCryptoProvider)o;
                    }
                    if (o instanceof Provider)
                    {
                        provider = (Provider)o;

                        return new JcaTlsCryptoProvider().setProvider(provider);
                    }

                    throw new IllegalArgumentException("unrecognized class: " + cryptoName);
                }
                catch (ClassNotFoundException e)
                {
                    throw new IllegalArgumentException("unable to find Provider/TlsCrypto class: " + cryptoName);
                }
                catch (InstantiationException e)
                {
                    throw new IllegalArgumentException("unable to create Provider/TlsCrypto class '" + cryptoName + "': " + e.getMessage(), e);
                }
                catch (IllegalAccessException e)
                {
                    throw new IllegalArgumentException("unable to create Provider/TlsCrypto class '" + cryptoName + "': " + e.getMessage(), e);
                }
            }
        }
    }

    // TODO: add a real fips mode
    private void configure(boolean isInFipsMode, final JcaTlsCryptoProvider baseCryptoProvider)
    {
        this.isInFipsMode = isInFipsMode;

        // TODO[jsse]: should X.509 be an alias.
        addAlgorithmImplementation("KeyManagerFactory.X.509", "org.bouncycastle.jsse.provider.KeyManagerFactory", new EngineCreator()
        {
            public Object createInstance(Object constructorParameter)
            {
                return new ProvKeyManagerFactorySpi();
            }
        });
        addAlias("Alg.Alias.KeyManagerFactory.X509", "X.509");
        addAlias("Alg.Alias.KeyManagerFactory.PKIX", "X.509");

        addAlgorithmImplementation("TrustManagerFactory.PKIX", "org.bouncycastle.jsse.provider.TrustManagerFactory", new EngineCreator()
        {
            public Object createInstance(Object constructorParameter)
            {
                return new ProvTrustManagerFactorySpi(baseCryptoProvider.getPkixProvider());
            }
        });
        addAlias("Alg.Alias.TrustManagerFactory.X.509", "PKIX");
        addAlias("Alg.Alias.TrustManagerFactory.X509", "PKIX");

//        if (isInFipsMode == false)
//        {
//            addAlgorithmImplementation("SSLContext.SSL", "org.bouncycastle.jsse.provider.SSLContext.SSL", new EngineCreator()
//            {
//                public Object createInstance(Object constructorParameter)
//                {
//                    return new ProvSSLContextSpi(baseCryptoProvider, new String[]{ "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" });
//                }
//            });
//            addAlgorithmImplementation("SSLContext.SSLv3", "org.bouncycastle.jsse.provider.SSLContext.SSLv3", new EngineCreator()
//            {
//                public Object createInstance(Object constructorParameter)
//                {
//                    return new ProvSSLContextSpi(baseCryptoProvider, new String[]{ "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" });
//                }
//            });
//        }

        addAlgorithmImplementation("SSLContext.TLS", "org.bouncycastle.jsse.provider.SSLContext.TLS", new EngineCreator()
        {
            public Object createInstance(Object constructorParameter)
            {
                return new ProvSSLContextSpi(baseCryptoProvider);
            }
        });
        addAlgorithmImplementation("SSLContext.TLSV1", "org.bouncycastle.jsse.provider.SSLContext.TLSv1", new EngineCreator()
        {
            public Object createInstance(Object constructorParameter)
            {
                return new ProvSSLContextSpi(baseCryptoProvider, new String[]{ "TLSv1", "TLSv1.1", "TLSv1.2" });
            }
        });
        addAlgorithmImplementation("SSLContext.TLSV1.1", "org.bouncycastle.jsse.provider.SSLContext.TLSv1_1", new EngineCreator()
        {
            public Object createInstance(Object constructorParameter)
            {
                return new ProvSSLContextSpi(baseCryptoProvider, new String[]{ "TLSv1.1", "TLSv1.2" });
            }
        });
        addAlgorithmImplementation("SSLContext.TLSV1.2", "org.bouncycastle.jsse.provider.SSLContext.TLSv1_2", new EngineCreator()
        {
            public Object createInstance(Object constructorParameter)
            {
                return new ProvSSLContextSpi(baseCryptoProvider);
            }
        });
        addAlgorithmImplementation("SSLContext.DEFAULT", "org.bouncycastle.jsse.provider.SSLContext.Default", new EngineCreator()
        {
            public Object createInstance(Object constructorParameter)
            {
                try
                {
                    ProvSSLContextSpi defaultSSLContextSpi = new ProvSSLContextSpi(baseCryptoProvider);
                    defaultSSLContextSpi.engineInit(null, null, null);
                    return defaultSSLContextSpi;
                }
                catch (GeneralSecurityException e)
                {
                    // TODO[jsse] Log this exception
                    return null;
                }
            }
        });
    }

    void addAttribute(String key, String attributeName, String attributeValue)
    {
        String attributeKey = key + " " + attributeName;
        if (containsKey(attributeKey))
        {
            throw new IllegalStateException("duplicate provider attribute key (" + attributeKey + ") found");
        }

        put(attributeKey, attributeValue);
    }

    void addAlgorithmImplementation(String key, String className, EngineCreator creator)
    {
        if (containsKey(key))
        {
            throw new IllegalStateException("duplicate provider key (" + key + ") found");
        }

        addAttribute(key, "ImplementedIn", "Software");

        put(key, className);
        creatorMap.put(className, creator);
    }

    void addAlias(String key, String value)
    {
        if (containsKey(key))
        {
            throw new IllegalStateException("duplicate provider key (" + key + ") found");
        }

        put(key, value);
    }

    public synchronized final Provider.Service getService(String type, String algorithm)
    {
        String upperCaseAlgName = Strings.toUpperCase(algorithm);

        BcJsseService service = serviceMap.get(type + "." + upperCaseAlgName);

        if (service == null)
        {
            String aliasString = "Alg.Alias." + type + ".";
            String realName = (String)this.get(aliasString + upperCaseAlgName);

            if (realName == null)
            {
                realName = upperCaseAlgName;
            }

            String className = (String)this.get(type + "." + realName);

            if (className == null)
            {
                return null;
            }

            String attributeKeyStart = type + "." + upperCaseAlgName + " ";

            List aliases = new ArrayList();
            Map attributes = new HashMap();

            for (Object key : this.keySet())
            {
                String sKey = (String)key;
                if (sKey.startsWith(aliasString))
                {
                    if (this.get(key).equals(algorithm))
                    {
                        aliases.add(sKey.substring(aliasString.length()));
                    }
                }
                if (sKey.startsWith(attributeKeyStart))
                {
                    attributes.put(sKey.substring(attributeKeyStart.length()), (String)this.get(sKey));
                }
            }

            service = new BcJsseService(this, type, upperCaseAlgName, className, aliases, getAttributeMap(attributes), creatorMap.get(className));

            serviceMap.put(type + "." + upperCaseAlgName, service);
        }

        return service;
    }

    public synchronized final Set getServices()
    {
        Set serviceSet = super.getServices();
        Set bcServiceSet = new HashSet();

        for (Provider.Service service: serviceSet)
        {
            bcServiceSet.add(getService(service.getType(), service.getAlgorithm()));
        }

        return bcServiceSet;
    }

    private static final Map, Map > attributeMaps = new HashMap, Map>();

    private static Map getAttributeMap(Map attributeMap)
    {
        Map attrMap = attributeMaps.get(attributeMap);
        if (attrMap != null)
        {
            return attrMap;
        }

        attributeMaps.put(attributeMap, attributeMap);

        return attributeMap;
    }

    public boolean isFipsMode()
    {
        return isInFipsMode;
    }

    private static class BcJsseService
        extends Provider.Service
    {
        private final EngineCreator creator;

        /**
         * Construct a new service.
         *
         * @param provider   the provider that offers this service
         * @param type       the type of this service
         * @param algorithm  the algorithm name
         * @param className  the name of the class implementing this service
         * @param aliases    List of aliases or null if algorithm has no aliases
         * @param attributes Map of attributes or null if this implementation
         *                   has no attributes
         * @throws NullPointerException if provider, type, algorithm, or
         * className is null
         */
        public BcJsseService(Provider provider, String type, String algorithm, String className, List aliases, Map attributes, EngineCreator creator)
        {
            super(provider, type, algorithm, className, aliases, attributes);
            this.creator = creator;
        }

        public Object newInstance(Object constructorParameter)
            throws NoSuchAlgorithmException
        {
            try
            {
                Object instance = creator.createInstance(constructorParameter);

                if (instance == null)
                {
                    throw new NoSuchAlgorithmException("No such algorithm in FIPS approved mode: " + getAlgorithm());
                }

                return instance;
            }
            catch (NoSuchAlgorithmException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                throw new NoSuchAlgorithmException("Unable to invoke creator for " + getAlgorithm() + ": " + e.getMessage(), e);
            }
        }
    }

//    private static final class FipsCapabilities
//        extends TlsCryptoCapabilities
//    {
//        public FipsCapabilities()
//        {
//            super(new int[]{ NamedCurve.secp256r1, NamedCurve.secp384r1 });
//        }
//    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy