SSLUtilities.java

/*
 * GovWay - A customizable API Gateway 
 * https://govway.org
 * 
 * Copyright (c) 2005-2024 Link.it srl (https://link.it). 
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3, as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package org.openspcoop2.utils.transport.http;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.security.Key;
import java.security.KeyStore;
import java.security.Provider;
import java.security.Provider.Service;
import java.security.Security;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.X509CRL;
import java.security.cert.X509CertSelector;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.net.ssl.CertPathTrustManagerParameters;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletRequest;

import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.openspcoop2.utils.Utilities;
import org.openspcoop2.utils.UtilsException;
import org.openspcoop2.utils.certificate.KeystoreType;
import org.openspcoop2.utils.certificate.KeystoreUtils;
import org.openspcoop2.utils.certificate.hsm.HSMManager;
import org.openspcoop2.utils.date.DateManager;
import org.openspcoop2.utils.random.RandomGenerator;
import org.openspcoop2.utils.resources.Loader;
import org.slf4j.Logger;

/**
 * SSLUtilities
 *
 * @author Poli Andrea (apoli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */
public class SSLUtilities {
	
	private SSLUtilities() {}
	
	
	private static String jvmHttpsClientCertificateConfigurated = null;
	private static synchronized void initJvmHttpsClientCertificateConfigurated() {
		if(jvmHttpsClientCertificateConfigurated==null) {
			jvmHttpsClientCertificateConfigurated = System.getProperty("javax.net.ssl.keyStore");
		}
	}
	public static boolean isJvmHttpsClientCertificateConfigurated() {
		if(jvmHttpsClientCertificateConfigurated==null) {
			initJvmHttpsClientCertificateConfigurated();
		}
		return jvmHttpsClientCertificateConfigurated!=null;
	}
	public static String getJvmHttpsClientCertificateConfigurated() {
		if(jvmHttpsClientCertificateConfigurated==null) {
			initJvmHttpsClientCertificateConfigurated();
		}
		return jvmHttpsClientCertificateConfigurated;
	}
	
	
	public static List<String> getSSLEnabledProtocols(String sslType) throws UtilsException{
		try{
			List<String> p = new ArrayList<>();
			SSLContext context = SSLContext.getInstance(sslType);
			context.init(null,null,null);
			SSLSocket socket = null;
			try {
				socket = (SSLSocket)context.getSocketFactory().createSocket();
				String[] protocols = socket.getEnabledProtocols();
				for (int i = 0; i < protocols.length; i++) {
					p.add(protocols[i]);
				}
			}finally {
				try {
					if(socket!=null) {
						socket.close();
					}
				}catch(Throwable t) {
					// ignore
				}
			}
			return p;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(), e);
		}
	}
	public static List<String> getSSLSupportedProtocols() throws UtilsException{
		try{
			List<String> p = new ArrayList<>();
			SSLContext defaultContext = SSLContext.getDefault();
			SSLSocket socket = null;
			try {
				socket = (SSLSocket)defaultContext.getSocketFactory().createSocket();
				String[] protocols = socket.getSupportedProtocols();
				for (int i = 0; i < protocols.length; i++) {
					p.add(protocols[i]);
				}
			}finally {
				try {
					if(socket!=null) {
						socket.close();
					}
				}catch(Throwable t) {
					// ignore
				}
			}
			return p;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(), e);
		}
	}
	public static String getSafeDefaultProtocol(){
		try{
			return getDefaultProtocol();
		}catch(Exception e){
			return SSLConstants.PROTOCOL_TLS;
		}
	}
	public static String getDefaultProtocol() throws UtilsException{
		// Ritorno l'ultima versione disponibile
		List<String> p = getSSLSupportedProtocols();
		if(p.contains(SSLConstants.PROTOCOL_TLS_V1_3)){
			return SSLConstants.PROTOCOL_TLS_V1_3;
		}
		else if(p.contains(SSLConstants.PROTOCOL_TLS_V1_2)){
			return SSLConstants.PROTOCOL_TLS_V1_2;
		}
		else if(p.contains(SSLConstants.PROTOCOL_TLS_V1_1)){
			return SSLConstants.PROTOCOL_TLS_V1_1;
		}
		else if(p.contains(SSLConstants.PROTOCOL_TLS_V1)){
			return SSLConstants.PROTOCOL_TLS_V1;
		}
		else if(p.contains(SSLConstants.PROTOCOL_TLS)){
			return SSLConstants.PROTOCOL_TLS;
		}
		else if(p.contains(SSLConstants.PROTOCOL_SSL_V3)){
			return SSLConstants.PROTOCOL_SSL_V3;
		}
		else if(p.contains(SSLConstants.PROTOCOL_SSL)){
			return SSLConstants.PROTOCOL_SSL;
		}
		else if(p.contains(SSLConstants.PROTOCOL_SSL_V2_HELLO)){
			return SSLConstants.PROTOCOL_SSL_V2_HELLO;
		}
		else{
			return p.get(0);
		}
	}
	public static List<String> getAllSslProtocol() {
		// ritorno in ordine dal più recente al meno recento, più altri eventuali protocolli.
		List<String> p = new ArrayList<>();
		p.add(SSLConstants.PROTOCOL_TLS_V1_2);
		p.add(SSLConstants.PROTOCOL_TLS_V1_1);
		p.add(SSLConstants.PROTOCOL_TLS_V1);
		p.add(SSLConstants.PROTOCOL_TLS); // per retrocompatibilità
		p.add(SSLConstants.PROTOCOL_SSL_V3);
		p.add(SSLConstants.PROTOCOL_SSL); // per retrocompatibilità
		p.add(SSLConstants.PROTOCOL_SSL_V2_HELLO);
		
		try{
			List<String> pTmp = getSSLSupportedProtocols();
			for (String s : pTmp) {
				if(p.contains(s)==false){
					p.add(s);
				}
			}
		}catch(Exception e){
			// non dovrebbe mai accadere una eccezione
			e.printStackTrace(System.err);
		}
			
		return  p;
	}
	
	public static List<String> getSSLEnabledCipherSuites(String sslType) throws UtilsException{
		try{
			List<String> l = new ArrayList<>();
			SSLContext context = SSLContext.getInstance(sslType);
			context.init(null,null,null);
			SSLSocket socket = null;
			try {
				socket = (SSLSocket)context.getSocketFactory().createSocket();
				String[] cs = socket.getEnabledCipherSuites();
				for (int i = 0; i < cs.length; i++) {
					l.add(cs[i]);
				}
			}finally {
				try {
					if(socket!=null) {
						socket.close();
					}
				}catch(Throwable t) {
					// ignore
				}
			}
			return l;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(), e);
		}
	}
	public static List<String> getSSLSupportedCipherSuites() throws UtilsException{
		try{
			List<String> l = new ArrayList<>();
			SSLContext defaultContext = SSLContext.getDefault();
			SSLSocket socket = null;
			try {
				socket = (SSLSocket)defaultContext.getSocketFactory().createSocket();
				String[] cs = socket.getSupportedCipherSuites();
				for (int i = 0; i < cs.length; i++) {
					l.add(cs[i]);
				}
			}finally {
				try {
					if(socket!=null) {
						socket.close();
					}
				}catch(Throwable t) {
					// ignore
				}
			}
			return l;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(), e);
		}
	}
		
	
	public static List<Provider> getSSLProviders() throws UtilsException{
		try{
			List<Provider> p = new ArrayList<>();
			for (Provider provider : Security.getProviders()){
				p.add(provider);
			}
			return p;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(), e);
		}
	}
	public static List<String> getSSLProvidersName() throws UtilsException{
		try{
			List<String> p = new ArrayList<>();
			for (Provider provider : Security.getProviders()){
				p.add(provider.getName());
			}
			return p;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(), e);
		}
	}
	public static List<String> getServiceTypes(Provider provider) throws UtilsException{
		try{
			List<String> p = new ArrayList<>();
			for (Service service : provider.getServices()){
				if(!p.contains(service.getType())){
					p.add(service.getType());
				}
			}
			return p;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(), e);
		}
	}
	public static List<String> getServiceTypeAlgorithms(Provider provider,String serviceType) throws UtilsException{
		try{
			List<String> p = new ArrayList<>();
			for (Service service : provider.getServices()){
				if(serviceType.equals(service.getType())){
					p.add(service.getAlgorithm());
				}
			}
			return p;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(), e);
		}
	}
	
	private static TrustManager[] trustAllCertsManager;
	private static synchronized void initTrustAllCertsManager() {
		if(trustAllCertsManager==null) {
			// Create a trust manager that does not validate certificate chains
			trustAllCertsManager = new TrustManager[]{
			    new SSLTrustAllManager()
			};
		}
	}
	public static TrustManager[] getTrustAllCertsManager() {
		if(trustAllCertsManager==null) {
			initTrustAllCertsManager();
		}
		return trustAllCertsManager;
	}
	
	public static SSLContext generateSSLContext(SSLConfig sslConfig, StringBuilder bfLog) throws UtilsException{
		return generateSSLContext(sslConfig, null, null, bfLog);
	}
	public static SSLContext generateSSLContext(SSLConfig sslConfig, IOCSPValidator ocspValidator, IBYOKUnwrapManager byok, StringBuilder bfLog) throws UtilsException{

		// Gestione https
		SSLContext sslContext = null;
		
		bfLog.append("Creo contesto SSL...\n");
		KeyManager[] km = null;
		TrustManager[] tm = null;

		InputStream finKeyStore = null;
		InputStream finTrustStore = null;
		try{
					
			// Autenticazione CLIENT
			if(sslConfig.getKeyStore()!=null || sslConfig.getKeyStoreLocation()!=null){
				bfLog.append("Gestione keystore...\n");
				bfLog.append("\tKeystore type["+sslConfig.getKeyStoreType()+"]\n");
				bfLog.append("\tKeystore location["+sslConfig.getKeyStoreLocation()+"]\n");
				/**bfLog.append("\tKeystore password["+sslConfig.getKeyStorePassword()+"]\n");*/
				bfLog.append("\tKeystore byok policy["+sslConfig.getKeyStoreBYOKPolicy()+"]\n");
				bfLog.append("\tKeystore keyManagementAlgorithm["+sslConfig.getKeyManagementAlgorithm()+"]\n");
				/**bfLog.append("\tKeystore keyPassword["+sslConfig.getKeyPassword()+"]\n");*/
				String location = null;
				try {
					location = sslConfig.getKeyStoreLocation(); // per debug
				
					boolean hsmKeystore = false;
					HSMManager hsmManager = HSMManager.getInstance();
					if(hsmManager!=null) {
						if(sslConfig.getKeyStore()!=null) {
							hsmKeystore = sslConfig.isKeyStoreHsm();
						}
						else {
							if(sslConfig.getKeyStoreType()!=null && hsmManager.existsKeystoreType(sslConfig.getKeyStoreType())) {
								hsmKeystore = true;
							}
						}
					}
					bfLog.append("\tKeystore HSM["+hsmManager+"]\n");
					
					KeyStore keystore = null;
					KeyStore keystoreParam = null;
					@SuppressWarnings("unused")
					Provider keystoreProvider = null;
					if(sslConfig.getKeyStore()!=null) {
						keystoreParam = sslConfig.getKeyStore();
						if(hsmKeystore) {
							keystoreProvider = keystoreParam.getProvider();
						}
					}
					else {
						if(hsmKeystore) {
							org.openspcoop2.utils.certificate.KeyStore ks = hsmManager.getKeystore(sslConfig.getKeyStoreType());
							if(ks==null) {
								throw new UtilsException("Keystore not found");
							}
							keystoreParam = ks.getKeystore();
							keystoreProvider = keystoreParam.getProvider();
						}
						else {
							File file = new File(location);
							if(file.exists()) {
								finKeyStore = new FileInputStream(file);
							}
							else {
								finKeyStore = SSLUtilities.class.getResourceAsStream(location);
							}
							if(finKeyStore == null) {
								throw new UtilsException("Keystore not found");
							}
							if(byok!=null) {
								byte [] keystoreEncBytes = Utilities.getAsByteArray(finKeyStore);
								byte [] keystorePlainBytes = byok.unwrap(keystoreEncBytes);
								keystoreParam = KeystoreUtils.readKeystore(keystorePlainBytes, sslConfig.getKeyStoreType(), sslConfig.getKeyStorePassword());
							}
							else {
								keystoreParam = KeystoreUtils.readKeystore(finKeyStore, sslConfig.getKeyStoreType(), sslConfig.getKeyStorePassword());
							}
						}
					}
					
					boolean oldMethodKeyAlias = false; // Questo metodo non funzionava con PKCS11
					if(oldMethodKeyAlias && sslConfig.getKeyAlias()!=null) {
						Key key = keystoreParam.getKey(sslConfig.getKeyAlias(), sslConfig.getKeyPassword().toCharArray());
						if(key==null) {
							throw new UtilsException("Key with alias '"+sslConfig.getKeyAlias()+"' not found");
						}
						if(hsmKeystore) {
							// uso un JKS come tmp
							keystore = KeyStore.getInstance(KeystoreType.JKS.getNome());
						}
						else {
							keystore = KeyStore.getInstance(sslConfig.getKeyStoreType());
						}
						keystore.load(null); // inizializza il keystore
						keystore.setKeyEntry(sslConfig.getKeyAlias(), key, 
								sslConfig.getKeyPassword().toCharArray(), keystoreParam.getCertificateChain(sslConfig.getKeyAlias()));
					}
					else {
						keystore = keystoreParam;
					}
					
					KeyManagerFactory keyManagerFactory = null;
					// NO: no such algorithm: SunX509 for provider SunPKCS11-xxx
					/**if(keystoreProvider!=null) {
					//	keyManagerFactory = KeyManagerFactory.getInstance(sslConfig.getKeyManagementAlgorithm(), keystoreProvider);
					//}
					//else {*/
					keyManagerFactory = KeyManagerFactory.getInstance(sslConfig.getKeyManagementAlgorithm());
					
					keyManagerFactory.init(keystore, sslConfig.getKeyPassword().toCharArray());
					km = keyManagerFactory.getKeyManagers();
					if(!oldMethodKeyAlias && sslConfig.getKeyAlias()!=null) {
						if(km!=null && km.length>0 && km[0]!=null && km[0] instanceof X509KeyManager) {
							
							String alias = sslConfig.getKeyAlias();
							
							// Fix case insensitive
							Enumeration<String> enAliases = keystore.aliases();
							if(enAliases!=null) {
								while (enAliases.hasMoreElements()) {
									String a = (String) enAliases.nextElement();
									if(a.equalsIgnoreCase(alias)) {
										alias = a; // uso quello presente nel keystore
										break;
									}
								}
							}
							
							X509KeyManager wrapperX509KeyManager = new SSLX509ManagerForcedClientAlias(alias, (X509KeyManager)km[0] );
							km[0] = wrapperX509KeyManager;
						}
					}
					bfLog.append("Gestione keystore effettuata\n");
				}catch(Throwable e) {
					if(location!=null) {
						throw new UtilsException("["+location+"] "+e.getMessage(),e);
					}
					else {
						throw new UtilsException(e.getMessage(),e);
					}
				}
			}
	
	
			// Autenticazione SERVER
			KeyStore truststoreParam = null;
			if(sslConfig.isTrustAllCerts()) {
				bfLog.append("Gestione trust all certs...\n");
				tm = getTrustAllCertsManager();
				bfLog.append("Gestione trust all certs effettuata\n");
			}
			else if(sslConfig.getTrustStore()!=null || sslConfig.getTrustStoreLocation()!=null){
				bfLog.append("Gestione truststore...\n");
				bfLog.append("\tTruststore type["+sslConfig.getTrustStoreType()+"]\n");
				bfLog.append("\tTruststore location["+sslConfig.getTrustStoreLocation()+"]\n");
				//bfLog.append("\tTruststore password["+sslConfig.getTrustStorePassword()+"]\n");
				bfLog.append("\tTruststore trustManagementAlgorithm["+sslConfig.getTrustManagementAlgorithm()+"]\n");
				String location = null;
				try {
					location = sslConfig.getTrustStoreLocation(); // per debug
					
					boolean hsmTruststore = false;
					HSMManager hsmManager = HSMManager.getInstance();
					if(hsmManager!=null) {
						if(sslConfig.getTrustStore()!=null) {
							hsmTruststore = sslConfig.isTrustStoreHsm();
						}
						else {
							if(sslConfig.getTrustStoreType()!=null && hsmManager.existsKeystoreType(sslConfig.getTrustStoreType())) {
								hsmTruststore = true;
							}
						}
					}
					bfLog.append("\tTruststore HSM["+hsmTruststore+"]\n");
					
					@SuppressWarnings("unused")
					Provider truststoreProvider = null;
					if(sslConfig.getTrustStore()!=null) {
						truststoreParam = sslConfig.getTrustStore();
						if(hsmTruststore) {
							truststoreProvider = truststoreParam.getProvider();
						}
					}
					else {
						if(hsmTruststore) {
							org.openspcoop2.utils.certificate.KeyStore ks = hsmManager.getKeystore(sslConfig.getTrustStoreType());
							if(ks==null) {
								throw new UtilsException("Truststore not found");
							}
							truststoreParam = ks.getKeystore();
							truststoreProvider = truststoreParam.getProvider();
						}
						else {
							File file = new File(location);
							if(file.exists()) {
								finTrustStore = new FileInputStream(file);
							}
							else {
								finTrustStore = SSLUtilities.class.getResourceAsStream(location);
							}
							if(finTrustStore == null) {
								throw new UtilsException("Truststore not found");
							}		
							truststoreParam = KeystoreUtils.readKeystore(finTrustStore, sslConfig.getTrustStoreType(), sslConfig.getTrustStorePassword());
						}
					}
					
					TrustManagerFactory trustManagerFactory = null;
					// NO: no such algorithm: PKIX for provider SunPKCS11-xxx
					/**if(truststoreProvider!=null) {
					//	trustManagerFactory = TrustManagerFactory.getInstance(sslConfig.getTrustManagementAlgorithm(), truststoreProvider);
					//}
					//else {*/
					trustManagerFactory = TrustManagerFactory.getInstance(sslConfig.getTrustManagementAlgorithm());
					
					String trustManagementAlgo = sslConfig.getTrustManagementAlgorithm();
					if(trustManagementAlgo!=null) {
						trustManagementAlgo = trustManagementAlgo.trim();
					}
					if("PKIX".equalsIgnoreCase(trustManagementAlgo)) {
					
						 // create the parameters for the validator
						if(sslConfig.getTrustStoreCRLs()!=null) {
							bfLog.append("\tTruststore CRLs\n");
						}
						else if(sslConfig.getTrustStoreCRLsLocation()!=null) {
							bfLog.append("\tTruststore CRLs["+sslConfig.getTrustStoreCRLsLocation()+"]\n");
						}
						
						Provider sigProvider = null;
						CertPathTrustManagerParameters params = buildCertPathTrustManagerParameters(truststoreParam, sslConfig.getTrustStoreCRLs(), sslConfig.getTrustStoreCRLsLocation(), sigProvider);
						trustManagerFactory.init(params);
						
					}
					else {
					
						trustManagerFactory.init(truststoreParam);
						
					}
					tm = trustManagerFactory.getTrustManagers();
					bfLog.append("Gestione truststore effettuata\n");
				}catch(Throwable e) {
					if(location!=null) {
						throw new UtilsException("["+location+"] "+e.getMessage(),e);
					}
					else {
						throw new UtilsException(e.getMessage(),e);
					}
				}
			}
			
			if(ocspValidator!=null) {
				if(ocspValidator.getTrustStore()==null && truststoreParam!=null) {
					ocspValidator.setTrustStore(new org.openspcoop2.utils.certificate.KeyStore(truststoreParam));
				}
				tm = OCSPTrustManager.wrap(tm, ocspValidator);
				ocspValidator.setOCSPTrustManager(OCSPTrustManager.read(tm));
			}
	
			// Creo contesto SSL
			bfLog.append("Init SSLContext type["+sslConfig.getSslType()+"] ...\n");
			sslContext = SSLContext.getInstance(sslConfig.getSslType());
			if(sslConfig.isSecureRandom()) {
				RandomGenerator randomGenerator = null;
				if(sslConfig.getSecureRandomAlgorithm()!=null && !"".equals(sslConfig.getSecureRandomAlgorithm())) {
					bfLog.append("Creazione Secure Random con algoritmo '"+sslConfig.getSecureRandomAlgorithm()+"' ...\n");
					randomGenerator = new RandomGenerator(true, sslConfig.getSecureRandomAlgorithm());
					bfLog.append("Creazione Secure Random con algoritmo '"+sslConfig.getSecureRandomAlgorithm()+"' effettuata\n");
				}
				else {
					bfLog.append("Creazione Secure Random ...\n");
					randomGenerator = new RandomGenerator(true);
					bfLog.append("Creazione Secure Random effettuata\n");
				}
				java.security.SecureRandom secureRandom = (java.security.SecureRandom) randomGenerator.getRandomEngine();
				bfLog.append("Inizializzazione SSLContext con Secure Random ...\n");
				sslContext.init(km, tm, secureRandom);
			}
			else {
				sslContext.init(km, tm, null);
			}
			
			
			if(sslContext.getClientSessionContext()!=null) {
				bfLog.append("ClientSessionContext size:").
					append(sslContext.getClientSessionContext().getSessionCacheSize()).
					append(" timeout:").
					append(sslContext.getClientSessionContext().getSessionTimeout()).append("\n");
			}
			if(sslContext.getServerSessionContext()!=null) {
				bfLog.append("ServerSessionContext size:").
					append(sslContext.getServerSessionContext().getSessionCacheSize()).
					append(" timeout:").
					append(sslContext.getServerSessionContext().getSessionTimeout()).append("\n");
			}
			
			bfLog.append("Init SSLContext type["+sslConfig.getSslType()+"] effettuato\n");
			
			return sslContext;
			
		}catch(Exception e){
			throw new UtilsException(e.getMessage(), e);
		}
		finally{
			try{
				if(finKeyStore!=null){
					finKeyStore.close();
				}
			}catch(Exception e){
				// close
			}
			try{
				if(finTrustStore!=null){
					finTrustStore.close();
				}
			}catch(Exception e){
				// close
			}
		}
	}
	
	public static CertPathTrustManagerParameters buildCertPathTrustManagerParameters(KeyStore truststoreParam,
			CertStore crlStore, String crlLocation, Provider provider) throws Exception {
		
		 // create the parameters for the validator
		
		// Ricreo il truststore altrimenti i certificati presenti come coppia (chiave privata e pubblica non sono trusted)
		KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType()); // JKS
		truststore.load(null); // inizializza il truststore
		Enumeration<String> aliases = truststoreParam.aliases();
		while (aliases.hasMoreElements()) {
			String alias = aliases.nextElement();
			/** System.out.println("ALIAS: '"+alias+"'"); */
			truststore.setCertificateEntry(alias, truststoreParam.getCertificate(alias));
		}
		
		PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(truststore, new X509CertSelector());
		pkixParams.setRevocationEnabled(false);
		pkixParams.setDate(DateManager.getDate());
		
		/**
		java.security.cert.PKIXRevocationChecker revocationChecker =
	            (java.security.cert.PKIXRevocationChecker) java.security.cert.CertPathBuilder.getInstance(trustManagementAlgo).getRevocationChecker();
	    pkixParams.addCertPathChecker(revocationChecker);
	    revocationChecker.setOcspResponder(uriResponse);
	    */
				        
		if(crlStore!=null || crlLocation!=null) {
	        CertStore crlsCertstore = null;
	        if(crlStore!=null) {
	        	crlsCertstore = crlStore;
	        }else {
	        	crlsCertstore = buildCRLCertStoreEngine(crlLocation);
	        }
	        pkixParams.addCertStore(crlsCertstore);
	        pkixParams.setRevocationEnabled(true);
		}
		
		if(provider!=null) {
			pkixParams.setSigProvider(provider.getName());
		}
		
		return new CertPathTrustManagerParameters(pkixParams);
		
	}
	
	private static CertStore buildCRLCertStoreEngine(String crlsPath) throws Exception {
    	List<byte[]> crlBytes = new ArrayList<>();
    	List<String> crlPathsList = new ArrayList<>();
		if(crlsPath.contains(",")) {
			String [] tmp = crlsPath.split(",");
			for (String crlPath : tmp) {
				crlPathsList.add(crlPath.trim());
			}
		}
		else {
			crlPathsList.add(crlsPath.trim());
		}
		for (String crlPath : crlPathsList) {
			InputStream isStore = null;
			try{
				File fStore = new File(crlPath);
				if(fStore.exists()){
					isStore = new FileInputStream(fStore);
				}else{
					isStore = SSLUtilities.class.getResourceAsStream(crlPath);
				}
				if(isStore==null){
					throw new UtilsException("CRL ["+crlPath+"] not found");
				}
				crlBytes.add(Utilities.getAsByteArray(isStore));
			}finally{
				try{
					if(isStore!=null){
						isStore.close();
					}
				}catch(Exception eClose){
					// close
				}
			}
		}
		List<X509CRL> caCrls = new ArrayList<>();
		CertificateFactory certFactory = org.openspcoop2.utils.certificate.CertificateFactory.getCertificateFactory();
    	for (int i = 0; i < crlBytes.size(); i++) {
			byte [] crl = crlBytes.get(i);
			try(ByteArrayInputStream bin = new ByteArrayInputStream(crl)){
				X509CRL caCrl = (X509CRL) certFactory.generateCRL(bin); 
				caCrls.add(caCrl);
			}
			catch(Exception e){
				throw new SecurityException("Error loading CRL '"+crlPathsList.get(i)+"': "+e.getMessage(),e);
			}
		}
		try {
			CollectionCertStoreParameters certStoreParams =
		                new CollectionCertStoreParameters(caCrls);
			return CertStore.getInstance("Collection", certStoreParams);
		}catch(Exception e){
			throw new SecurityException("Build CertStore failed: "+e.getMessage(),e);
		}
	}

	
	public static HostnameVerifier generateHostnameVerifier(SSLConfig sslConfig, StringBuilder bfLog, Logger log, Loader loader) throws UtilsException{
		try{
			if(sslConfig.isHostnameVerifier()){
				if(sslConfig.getClassNameHostnameVerifier()!=null){
					bfLog.append("HostNamve verifier enabled ["+sslConfig.getClassNameHostnameVerifier()+"]\n");
					return (HostnameVerifier) loader.newInstance(sslConfig.getClassNameHostnameVerifier());
				}else{
					bfLog.append("HostName verifier enabled\n");
					return null;
				}
			}else{
				bfLog.append("HostName verifier disabled\n");
				SSLHostNameVerifierDisabled disabilitato = new SSLHostNameVerifierDisabled(log);
				return disabilitato;
			}
		}catch(Exception e){
			throw new UtilsException(e.getMessage(), e);
		}
		
	}
	
	
	public static void setSSLContextIntoJavaProperties(SSLConfig sslConfig, StringBuilder bfLog) throws UtilsException{

		bfLog.append("Creo contesto SSL...\n");

		try{
		
			// Autenticazione CLIENT
			if(sslConfig.getKeyStoreLocation()!=null){
				bfLog.append("Gestione keystore...\n");
				
				System.setProperty("javax.net.ssl.keyStore", sslConfig.getKeyStoreLocation());
				if(sslConfig.getKeyStoreType()!=null){
					System.setProperty("javax.net.ssl.keyStoreType", sslConfig.getKeyStoreType());
				}
				if(sslConfig.getKeyStorePassword()!=null){
					System.setProperty("javax.net.ssl.keyStorePassword", sslConfig.getKeyStorePassword());
				}
				if(sslConfig.getKeyPassword()!=null){
					System.setProperty("javax.net.ssl.keyStorePassword", sslConfig.getKeyStorePassword());
					if(sslConfig.getKeyStorePassword()!=null){
						if(!sslConfig.getKeyPassword().equals(sslConfig.getKeyStorePassword())){
							throw new UtilsException("Keystore and key password in java must be equals");
						}
					}
				}
				
				bfLog.append("Gestione keystore effettuata\n");
			}
	
	
			// Autenticazione SERVER
			if(sslConfig.getTrustStoreLocation()!=null){
				bfLog.append("Gestione truststore...\n");
				
				System.setProperty("javax.net.ssl.trustStore", sslConfig.getTrustStoreLocation());
				if(sslConfig.getKeyStoreType()!=null){
					System.setProperty("javax.net.ssl.trustStoreType", sslConfig.getTrustStoreType());
				}
				if(sslConfig.getKeyStorePassword()!=null){
					System.setProperty("javax.net.ssl.trustStorePassword", sslConfig.getTrustStorePassword());
				}
				
				bfLog.append("Gestione truststore effettuata\n");
			}
			
		}catch(Exception e){
			throw new UtilsException(e.getMessage(), e);
		}

	}
	
	public static String readPeerCertificates(String host, int port) throws UtilsException{
		try {
			
			SSLContext sslContext = SSLContext.getInstance(SSLUtilities.getDefaultProtocol());
			KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
			TrustManagerFactory tmf =
                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(ks);
            X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
            SSLSavingTrustManager   tm = new SSLSavingTrustManager(defaultTrustManager);
            sslContext.init(null, new TrustManager[] {tm}, null);
			
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            
            SSLSocket sslSocket = null;
			try {
				sslSocket = (SSLSocket) sslSocketFactory.createSocket(host, port);
	    		sslSocket.setSoTimeout(10000);
	    		sslSocket.setWantClientAuth(false);
	    		try {
	    			sslSocket.startHandshake();
	    		}catch(Throwable t) {
	    			// ignore
	    		}
			}finally {
				try {
					if(sslSocket!=null) {
						sslSocket.close();
					}
				}catch(Throwable t) {
					// ignore
				}
			}
    		Certificate [] certs = tm.getPeerCertificates();
    		if(certs == null || certs.length<=0) {
    			throw new UtilsException("Peer Certificates not found");
    		}
    		StringBuilder sb = new StringBuilder();
    		for (Certificate certificate : certs) {

    			StringWriter sw = new StringWriter();
    			JcaPEMWriter pemWriter = new JcaPEMWriter(sw);
    			pemWriter.writeObject(certificate);
    			pemWriter.close();
    			sw.close();
    			sb.append(sw.toString());

    		}
    		
    		return sb.toString();
            
		}catch(Exception e){
			throw new UtilsException(e.getMessage(), e);
		}
	}
	
	public static java.security.cert.X509Certificate[] readCertificatesFromUndertowServlet(HttpServletRequest req) {
		return readCertificatesFromUndertowServlet(req, null);
	}
	public static java.security.cert.X509Certificate[] readCertificatesFromUndertowServlet(HttpServletRequest reqParam, Logger log) {
		try {
			HttpServletRequest req = reqParam;
			if(reqParam instanceof WrappedHttpServletRequest) {
				req = ((WrappedHttpServletRequest)reqParam).httpServletRequest;
			}
			
			String undertow = "io.undertow.servlet.spec.HttpServletRequestImpl";
			String actual = req.getClass().getName() + "";
			boolean isUndertow = undertow.equals(actual);
			
			if(isUndertow) {
				
				// io/undertow/server/HttpServerExchange.java
				Method mExchange = req.getClass().getMethod("getExchange");
				if(mExchange!=null) {
					Object exchange = mExchange.invoke(req);
					if(exchange!=null) {
						/**System.out.println("Exchange ["+exchange.getClass().getName()+"]");*/
						
						// io/undertow/server/ServerConnection.java
						Method mConnection = exchange.getClass().getMethod("getConnection");
						if(mConnection!=null) {
							Object connection = mConnection.invoke(exchange);
							if(connection!=null) {
								/**System.out.println("Connection ["+connection.getClass().getName()+"]");*/
								
								// io/undertow/server/SSLSessionInfo.java
								Method mSSLSessionInfo = connection.getClass().getMethod("getSslSessionInfo");
								if(mSSLSessionInfo!=null) {
									Object sslSessionInfo = mSSLSessionInfo.invoke(connection);
									if(sslSessionInfo!=null) {
										/**System.out.println("sslSessionInfo ["+sslSessionInfo.getClass().getName()+"]");*/
										
										Method mPeerCertificates = sslSessionInfo.getClass().getMethod("getPeerCertificates");
										if(mPeerCertificates!=null) {
											try {
												Object peerCertificates = mPeerCertificates.invoke(sslSessionInfo);
												if(peerCertificates instanceof java.security.cert.X509Certificate[]) {
													return (java.security.cert.X509Certificate[]) peerCertificates;
												}
											}catch(Throwable t) {
												// a volte lancia eccezione null .... 
												if(Utilities.existsInnerException(t, "io.undertow.server.RenegotiationRequiredException")) {
													return null; // certificati non sono disponibili a causa di una rinegoziazione
												}
												else {
													if(log!=null) {
														log.error("readCertificatesFromUndertowServlet 'get peer certificates' failed: "+t.getMessage(),t);
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}catch(Throwable t) {
			if(log!=null) {
				log.error("readCertificatesFromUndertowServlet failed: "+t.getMessage(),t);
			}
		}
		return null;
	}
}