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

ch.csnc.extension.httpclient.SSLContextManager Maven / Gradle / Ivy

Go to download

The Zed Attack Proxy (ZAP) is an easy to use integrated penetration testing tool for finding vulnerabilities in web applications. It is designed to be used by people with a wide range of security experience and as such is ideal for developers and functional testers who are new to penetration testing. ZAP provides automated scanners as well as a set of tools that allow you to find security vulnerabilities manually.

There is a newer version: 2.15.0
Show newest version
/*
 * This file is part of WebScarab, an Open Web Application Security
 * Project utility. For details, please see http://www.owasp.org/
 *
 * Copyright (c) 2002 - 2004 Rogan Dawes
 *
 * Please note that this file was originally released under the
 * GNU General Public License  as published by the Free Software Foundation;
 * either version 2 of the License, or (at your option) any later version.
 *
 * As of October 2014 Rogan Dawes granted the OWASP ZAP Project permission to
 * redistribute this code under the Apache License, Version 2.0:
 *
 *
 * Licensed 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 ch.csnc.extension.httpclient;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class SSLContextManager {

    /** The canonical class name of Sun PKCS#11 Provider. */
    public static final String SUN_PKCS11_CANONICAL_CLASS_NAME = "sun.security.pkcs11.SunPKCS11";

    /** The canonical class name of IBMPKCS11Impl Provider. */
    public static final String IBM_PKCS11_CANONICAL_CLASS_NAME =
            "com.ibm.crypto.pkcs11impl.provider.IBMPKCS11Impl";

    /** @deprecated (2.11.0) Use {@link #IBM_PKCS11_CANONICAL_CLASS_NAME} */
    @Deprecated
    public static final String IBM_PKCS11_CONONICAL_CLASS_NAME = IBM_PKCS11_CANONICAL_CLASS_NAME;

    /** The name of Sun PKCS#11 Provider. */
    private static final String SUN_PKCS11_PROVIDER_NAME = "SunPKCS11";

    /**
     * The name for providers of type PKCS#11.
     *
     * @see #isProviderAvailable(String)
     */
    public static final String PKCS11_PROVIDER_TYPE = "PKCS11";

    /**
     * The name of the {@code KeyStore} type of Sun PKCS#11 Provider.
     *
     * @see KeyStore#getInstance(String, Provider)
     */
    private static final String SUN_PKCS11_KEYSTORE_TYPE = "PKCS11";

    /**
     * The name of the {@code KeyStore} type of IBMPKCS11Impl Provider.
     *
     * @see KeyStore#getInstance(String, Provider)
     */
    private static final String IBM_PKCS11_KEYSTORE_TYPE = "PKCS11IMPLKS";

    /**
     * Flag that indicates if the check for Java 9 and SunPKCS11 was already done.
     *
     * @see #isJava9SunPKCS11()
     */
    private static Boolean java9SunPKCS11;

    private Map _contextMaps = new TreeMap<>();
    private SSLContext _noClientCertContext;
    private String _defaultKey = null;
    private Map> _aliasPasswords = new HashMap<>();
    private List _keyStores = new ArrayList<>();
    private Map _keyStoreDescriptions = new HashMap<>();
    private Map _keyStorePasswords = new HashMap<>();

    private static Logger log = LogManager.getLogger(SSLContextManager.class);

    private static TrustManager[] _trustAllCerts =
            new TrustManager[] {
                new X509TrustManager() {
                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    @Override
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {}

                    @Override
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {}
                }
            };

    private int _defaultKeystoreIndex = -1;
    private int _defaultAliasIndex = -1;

    /** Creates a new instance of SSLContextManager */
    public SSLContextManager() {
        try {
            _noClientCertContext = SSLContext.getInstance("SSL");
            _noClientCertContext.init(null, _trustAllCerts, new SecureRandom());
        } catch (NoSuchAlgorithmException nsao) {
            log.error("Could not get an instance of the SSL algorithm: " + nsao.getMessage(), nsao);
        } catch (KeyManagementException kme) {
            log.error("Error initialising the SSL Context:  " + kme.getMessage(), kme);
        }

        try {
            initMSCAPI();
        } catch (Exception e) {
        }
    }

    public boolean isProviderAvailable(String type) {
        try {
            if (type.equals(PKCS11_PROVIDER_TYPE)) {
                try {
                    Class.forName(SUN_PKCS11_CANONICAL_CLASS_NAME);
                    return true;
                } catch (Throwable ignore) {
                    Class.forName(IBM_PKCS11_CANONICAL_CLASS_NAME);
                    return true;
                }
            } else if (type.equals("msks")) {
                Class.forName("se.assembla.jce.provider.ms.MSProvider");
                return true;
            }
        } catch (Throwable ignore) {
        }
        return false;
    }

    private int addKeyStore(KeyStore ks, String description, String password) {
        int index = _keyStores.indexOf(ks);
        if (index == -1) {
            _keyStores.add(ks);
            index = _keyStores.size() - 1;
        }
        _keyStoreDescriptions.put(ks, description);
        _keyStorePasswords.put(ks, password);
        return index;
    }

    public boolean removeKeyStore(int keystoreIndex) {
        boolean isDefaultKeyStore = (keystoreIndex == _defaultKeystoreIndex);
        KeyStore ks = _keyStores.get(keystoreIndex);

        _keyStores.remove(ks);
        _keyStoreDescriptions.remove(ks);
        _keyStorePasswords.remove(ks);

        if (isDefaultKeyStore) {
            _defaultKeystoreIndex = -1;
            _defaultAliasIndex = -1;
        }
        return isDefaultKeyStore;
    }

    public int getKeyStoreCount() {
        return _keyStores.size();
    }

    public String getKeyStoreDescription(int keystoreIndex) {
        return _keyStoreDescriptions.get(_keyStores.get(keystoreIndex));
    }

    public String getKeyStorePassword(int keystoreIndex) {
        return _keyStorePasswords.get(_keyStores.get(keystoreIndex));
    }

    public int getAliasCount(int keystoreIndex) {
        return getAliases(_keyStores.get(keystoreIndex)).size();
    }

    public String getAliasAt(int keystoreIndex, int aliasIndex) {
        return getAliases(_keyStores.get(keystoreIndex)).get(aliasIndex).getAlias();
    }

    private List getAliases(KeyStore ks) {
        List aliases = new ArrayList<>();
        try {
            Enumeration en = ks.aliases();

            boolean isIbm = isIbmPKCS11Provider();
            while (en.hasMoreElements()) {
                String alias = en.nextElement();
                // Sun's and IBM's KeyStore implementations behave differently...
                // With IBM's KeyStore impl #getCertificate(String) returns null when
                // #isKeyEntry(String) returns true.
                // If IBM add all certificates and let the user choose the correct one.
                if (ks.isKeyEntry(alias) || (isIbm && ks.isCertificateEntry(alias))) {
                    Certificate cert = ks.getCertificate(alias);
                    // IBM: Maybe we should check the KeyUsage?
                    // ((X509Certificate) cert).getKeyUsage()[0]
                    AliasCertificate aliasCert = new AliasCertificate(cert, alias);
                    aliases.add(aliasCert);
                }
            }
        } catch (KeyStoreException kse) {
            kse.printStackTrace();
        }
        return aliases;
    }

    public List getAliases(int ks) {
        return getAliases(_keyStores.get(ks));
    }

    public Certificate getCertificate(int keystoreIndex, int aliasIndex) {
        try {
            KeyStore ks = _keyStores.get(keystoreIndex);
            String alias = getAliasAt(keystoreIndex, aliasIndex);
            return ks.getCertificate(alias);
        } catch (Exception e) {
            return null;
        }
    }

    public String getFingerPrint(Certificate cert) throws KeyStoreException {
        if (!(cert instanceof X509Certificate)) {
            return null;
        }

        StringBuilder buff = new StringBuilder();
        X509Certificate x509 = (X509Certificate) cert;

        try {
            String fingerprint = DigestUtils.md5Hex(cert.getEncoded());
            for (int i = 0; i < fingerprint.length(); i += 2) {
                buff.append(fingerprint.substring(i, i + 1)).append(":");
            }
            buff.deleteCharAt(buff.length() - 1);
        } catch (CertificateEncodingException e) {
            throw new KeyStoreException(e.getMessage());
        }

        String dn = x509.getSubjectX500Principal().getName();

        log.info("Fingerprint is " + buff.toString().toUpperCase());

        return buff.toString().toUpperCase() + " " + dn;
    }

    public boolean isKeyUnlocked(int keystoreIndex, int aliasIndex) {
        KeyStore ks = _keyStores.get(keystoreIndex);
        String alias = getAliasAt(keystoreIndex, aliasIndex);

        Map pwmap = _aliasPasswords.get(ks);
        if (pwmap == null) {
            return false;
        }

        return pwmap.containsKey(alias);
    }

    public void setDefaultKey(int keystoreIndex, int aliasIndex) throws KeyStoreException {

        _defaultKeystoreIndex = keystoreIndex;
        _defaultAliasIndex = aliasIndex;

        if ((_defaultKeystoreIndex == -1) || (_defaultAliasIndex == -1)) {
            _defaultKey = "";
        } else {
            _defaultKey = getFingerPrint(getCertificate(keystoreIndex, aliasIndex));
        }
    }

    public String getDefaultKey() {
        return _defaultKey;
    }

    public Certificate getDefaultCertificate() {
        return getCertificate(_defaultKeystoreIndex, _defaultAliasIndex);
    }

    public int initMSCAPI()
            throws KeyStoreException, NoSuchProviderException, IOException,
                    NoSuchAlgorithmException, CertificateException {
        try {
            if (!isProviderAvailable("msks")) {
                return -1;
            }

            Provider mscapi =
                    (Provider)
                            Class.forName("se.assembla.jce.provider.ms.MSProvider")
                                    .getDeclaredConstructor()
                                    .newInstance();
            Security.addProvider(mscapi);

            // init the key store
            KeyStore ks = KeyStore.getInstance("msks", "assembla");
            ks.load(null, null);

            return addKeyStore(ks, "Microsoft CAPI Store", null);

        } catch (Exception e) {
            log.error("Error instantiating the MSCAPI provider: " + e.getMessage(), e);
            return -1;
        }
    }

    /*
     * public int initCryptoApi() throws KeyStoreException,
     * NoSuchAlgorithmException, CertificateException, IOException{
     *
     * Provider mscapi = new sun.security.mscapi.SunMSCAPI();
     * Security.addProvider(mscapi);
     *
     * KeyStore ks = KeyStore.getInstance("Windows-MY"); ks.load(null, null);
     *
     * return addKeyStore(ks, "CryptoAPI", null); }
     */
    public int initPKCS11(PKCS11Configuration configuration, String kspassword)
            throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException,
                    ClassNotFoundException, SecurityException, NoSuchMethodException,
                    IllegalArgumentException, InstantiationException, IllegalAccessException,
                    InvocationTargetException {

        if (!isProviderAvailable(PKCS11_PROVIDER_TYPE)) {
            return -1;
        }

        Provider pkcs11 = createPKCS11Provider(configuration);

        Security.addProvider(pkcs11);

        // init the key store
        KeyStore ks = getPKCS11KeyStore(pkcs11.getName());
        ks.load(null, kspassword == null ? null : kspassword.toCharArray());
        return addKeyStore(ks, "PKCS#11: " + configuration.getName(), ""); // do not store pin code
    }

    private static Provider createPKCS11Provider(PKCS11Configuration configuration)
            throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
                    IllegalAccessException, InvocationTargetException, IOException {
        Provider pkcs11 = null;
        if (isSunPKCS11Provider()) {
            if (isJava9SunPKCS11()) {
                Provider provider = Security.getProvider(SUN_PKCS11_PROVIDER_NAME);
                Method configure = provider.getClass().getMethod("configure", String.class);
                File configFile = File.createTempFile("pkcs11", ".cfg");
                configFile.deleteOnExit();
                FileUtils.write(configFile, configuration.toString(), StandardCharsets.UTF_8);
                pkcs11 = (Provider) configure.invoke(provider, configFile.getAbsolutePath());
            } else {
                pkcs11 =
                        createInstance(
                                SUN_PKCS11_CANONICAL_CLASS_NAME,
                                InputStream.class,
                                configuration.toInpuStream());
            }
        } else if (isIbmPKCS11Provider()) {
            pkcs11 =
                    createInstance(
                            IBM_PKCS11_CANONICAL_CLASS_NAME,
                            BufferedReader.class,
                            new BufferedReader(
                                    new InputStreamReader(configuration.toInpuStream())));
        }
        return pkcs11;
    }

    private static Provider createInstance(String name, Class paramClass, Object param)
            throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
                    IllegalAccessException, InvocationTargetException {
        Class instanceClass = Class.forName(name);
        Constructor c = instanceClass.getConstructor(new Class[] {paramClass});
        return (Provider) c.newInstance(new Object[] {param});
    }

    private static boolean isSunPKCS11Provider() {
        try {
            Class.forName(SUN_PKCS11_CANONICAL_CLASS_NAME);
            return true;
        } catch (Throwable ignore) {
        }
        return false;
    }

    private static boolean isJava9SunPKCS11() {
        if (java9SunPKCS11 != null) {
            return java9SunPKCS11;
        }

        java9SunPKCS11 = Boolean.FALSE;
        try {
            Provider provider = Security.getProvider(SUN_PKCS11_PROVIDER_NAME);
            if (provider != null) {
                provider.getClass().getMethod("configure", String.class);
                java9SunPKCS11 = Boolean.TRUE;
            }
        } catch (NoSuchMethodException ignore) {
            // The provider/method is available only in Java 9+.
        }
        return java9SunPKCS11;
    }

    private static boolean isIbmPKCS11Provider() {
        try {
            Class.forName(IBM_PKCS11_CANONICAL_CLASS_NAME);
            return true;
        } catch (Throwable ignore) {
        }
        return false;
    }

    private static KeyStore getPKCS11KeyStore(String providerName) throws KeyStoreException {
        String keyStoreType = SUN_PKCS11_KEYSTORE_TYPE;
        if (isIbmPKCS11Provider()) {
            keyStoreType = IBM_PKCS11_KEYSTORE_TYPE;
        }
        return KeyStore.getInstance(keyStoreType, Security.getProvider(providerName));
    }

    public int loadPKCS12Certificate(String filename, String ksPassword)
            throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {

        // Get Filename
        File file = new File(filename);
        if (!file.exists()) {
            throw new FileNotFoundException(filename + " could not be found");
        }
        String name = file.getName();

        // Open the file
        try (InputStream is = new FileInputStream(file)) {
            // create the keystore
            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(is, ksPassword == null ? null : ksPassword.toCharArray());
            return addKeyStore(ks, "PKCS#12: " + name, ksPassword);
        }
    }

    public boolean unlockKeyWithDefaultPassword(int keystoreIndex, int aliasIndex)
            throws KeyManagementException, KeyStoreException {

        return unlockKey(keystoreIndex, aliasIndex, getKeyStorePassword(keystoreIndex));
    }

    public boolean unlockKey(int keystoreIndex, int aliasIndex, String keyPassword)
            throws KeyStoreException, KeyManagementException {

        KeyStore ks = _keyStores.get(keystoreIndex);
        String alias = getAliasAt(keystoreIndex, aliasIndex);

        AliasKeyManager akm = new AliasKeyManager(ks, alias, keyPassword);

        try {
            akm.getPrivateKey(alias).toString();
        } catch (NullPointerException ex) {
            log.error("Could not get private key: " + ex.getMessage(), ex);
            return false;
        }

        String fingerprint = getFingerPrint(getCertificate(keystoreIndex, aliasIndex));

        if (fingerprint == null) {
            log.info("No fingerprint found");
            return false;
        }

        SSLContext sc;
        try {
            sc = SSLContext.getInstance("SSL");
        } catch (NoSuchAlgorithmException nsao) {
            log.error("Could not get an instance of the SSL algorithm: " + nsao.getMessage(), nsao);
            return false;
        }

        sc.init(new KeyManager[] {akm}, _trustAllCerts, new SecureRandom());

        String key = fingerprint;
        if (key.indexOf(" ") > 0) {
            key = key.substring(0, key.indexOf(" "));
        }

        _contextMaps.put(key, sc);
        log.info("Key has been unlocked.");

        return true;
    }

    public void invalidateSessions() {
        invalidateSession(_noClientCertContext);
        Iterator it = _contextMaps.keySet().iterator();
        while (it.hasNext()) {
            invalidateSession(_contextMaps.get(it.next()));
        }
    }

    private void invalidateSession(SSLContext sc) {
        SSLSessionContext sslsc = sc.getClientSessionContext();
        if (sslsc != null) {
            int timeout = sslsc.getSessionTimeout();
            // force sessions to be timed out
            sslsc.setSessionTimeout(1);
            sslsc.setSessionTimeout(timeout);
        }
        sslsc = sc.getServerSessionContext();
        if (sslsc != null) {
            int timeout = sslsc.getSessionTimeout();
            // force sessions to be timed out
            sslsc.setSessionTimeout(1);
            sslsc.setSessionTimeout(timeout);
        }
    }

    public SSLContext getSSLContext(String fingerprint) {
        log.info("Requested SSLContext for " + fingerprint);

        if (fingerprint == null || fingerprint.equals("none")) {
            return _noClientCertContext;
        }

        if (fingerprint.indexOf(" ") > 0) {
            fingerprint = fingerprint.substring(0, fingerprint.indexOf(" "));
        }

        return _contextMaps.get(fingerprint);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy