KeyStore.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.certificate;

import java.io.File;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.SecretKey;
import javax.security.auth.x500.X500Principal;

import org.apache.cxf.common.util.Base64UrlUtility;
import org.apache.cxf.rt.security.crypto.MessageDigestUtils;
import org.openspcoop2.utils.UtilsException;
import org.openspcoop2.utils.resources.FileSystemUtilities;

/**	
 * Keystore
 *
 * @author Poli Andrea (apoli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */
public class KeyStore {
	
	private java.security.KeyStore keystoreArchive;
	private boolean keystoreHsm;
	
	public KeyStore(String keystorePath,String passwordKeystore) throws UtilsException{
		this(keystorePath,KeystoreType.JKS.getNome(),passwordKeystore);
	}
	public KeyStore(String keystorePath,String tipoKeystore, String passwordKeystore) throws UtilsException{
		this(new File(keystorePath),tipoKeystore,passwordKeystore);
	}
	public KeyStore(File keystorePath,String passwordKeystore) throws UtilsException{
		this(keystorePath,KeystoreType.JKS.getNome(),passwordKeystore);
	}
	public KeyStore(File keystorePath,String tipoKeystore, String passwordKeystore) throws UtilsException{
		
		if(!keystorePath.exists()){
			throw new UtilsException("Keystore ["+keystorePath+"] not exists");
		}
		if(!keystorePath.canRead()){
			throw new UtilsException("Keystore ["+keystorePath+"] cannot read");
		}
		
		byte [] keystore = null;
		try {
			keystore = FileSystemUtilities.readBytesFromFile(keystorePath);
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}
		
		this.keystoreArchive = KeystoreUtils.readKeystore(keystore, tipoKeystore, passwordKeystore);
	}
	
	public KeyStore(byte[] keystore,String passwordKeystore) throws UtilsException{
		this(keystore,KeystoreType.JKS.getNome(),passwordKeystore);
	}
	public KeyStore(byte[] keystore,String tipoKeystore, String passwordKeystore) throws UtilsException{
		
		if(keystore==null){
			throw new UtilsException("Keystore undefined");
		}
		
		this.keystoreArchive = KeystoreUtils.readKeystore(keystore, tipoKeystore, passwordKeystore);
		
	}
	
	
	public KeyStore(java.security.KeyStore keystore) {
		this(keystore, false);
	}
	public KeyStore(java.security.KeyStore keystore, boolean keystoreHsm) {
		this.keystoreArchive = keystore;
		this.keystoreHsm = keystoreHsm;
	}
	
	private Map<String, Key> keys = new HashMap<>(); // effettuo il cache delle chiavi essendo costoso accederci tutte le volte
	private synchronized void initKey(String alias, String password) throws UtilsException {
		if(!this.keys.containsKey(alias)) {
			try{
				/** System.out.println("******** AGGIUNGO CHIAVE '"+alias+"' IN CACHE!!!!!!!!"); */
				Key key = null;
				if(password!=null) {
					key = this.keystoreArchive.getKey(alias, password.toCharArray());
				}
				else {
					key = this.keystoreArchive.getKey(alias, null);
				}
				if(key==null) {
					throw new UtilsException("Not found");
				}
				this.keys.put(alias, key);
			}catch(Exception e){
				throw new UtilsException(e.getMessage(),e);
			}
		}
	}
	
	public PrivateKey getPrivateKey(String alias,String passwordPrivateKey) throws UtilsException{
		try{
			if(!this.keys.containsKey(alias)) {
				initKey(alias, passwordPrivateKey);
			}
/**			else {
//				System.out.println("GET KEY '"+alias+"' FROM CACHE");
//			} */
			return (PrivateKey) this.keys.get(alias);
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}	
	}
	public SecretKey getSecretKey(String alias,String passwordPrivateKey) throws UtilsException{
		try{
			if(!this.keys.containsKey(alias)) {
				initKey(alias, passwordPrivateKey);
			}
			return (SecretKey) this.keys.get(alias);
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}	
	}

	public Certificate getCertificate() throws UtilsException{
		try{
			Enumeration<String> aliases = this.keystoreArchive.aliases();
			Certificate cer = null;
			while (aliases.hasMoreElements()) {
				String alias = aliases.nextElement();
				if(cer!=null){
					throw new UtilsException("More than one certificate, use alias");
				}
				cer = this.keystoreArchive.getCertificate(alias);
			}
			return cer;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}	
	}
	public Certificate getCertificate(String alias) throws UtilsException{
		try{
			return this.keystoreArchive.getCertificate(alias);
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}	
	}
	public Certificate[] getCertificateChain(String alias) throws UtilsException{
		try{
			return this.keystoreArchive.getCertificateChain(alias);
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}	
	}
	
	public Certificate getCertificateByDigestMD5UrlEncoded(String digest) throws UtilsException{
		return getCertificateByDigestUrlEncoded(digest, MessageDigestUtils.ALGO_MD5);
	}
	public Certificate getCertificateByDigestSHA1UrlEncoded(String digest) throws UtilsException{
		return getCertificateByDigestUrlEncoded(digest, MessageDigestUtils.ALGO_SHA_1);
	}
	public Certificate getCertificateByDigestSHA256UrlEncoded(String digest) throws UtilsException{
		return getCertificateByDigestUrlEncoded(digest, MessageDigestUtils.ALGO_SHA_256);
	}
	public Certificate getCertificateByDigestUrlEncoded(String digest, String digestAlgo) throws UtilsException{
		try{
			Enumeration<String> aliases = this.keystoreArchive.aliases();
			while (aliases.hasMoreElements()) {
				String alias = aliases.nextElement();
				Certificate cer = this.keystoreArchive.getCertificate(alias);
				String digestCer = this.buildDigestUrlEncoded(cer, digestAlgo);
				if(digestCer.equals(digest)) {
					return cer;
				}
			}
			return null;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}	
	}
	
	public Certificate getCertificateBySubject(X500Principal principal) throws UtilsException{
		try{
			if(principal==null) {
				return null;
			}
			Enumeration<String> aliases = this.keystoreArchive.aliases();
			while (aliases.hasMoreElements()) {
				String alias = aliases.nextElement();
				Certificate cer = this.keystoreArchive.getCertificate(alias);
				if(cer instanceof X509Certificate) {
					X509Certificate x509 = (X509Certificate) cer;
					X500Principal subject = x509.getSubjectX500Principal();
					if(principal.equals(subject)) {
						return cer;
					}
				}
			}
			return null;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}	
	}
	public boolean existsCertificateBySubject(X500Principal principal) throws UtilsException{
		try{
			return this.getCertificateBySubject(principal)!=null;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}	
	}
	
	public Certificate getCertificateByPublicKey(PublicKey publicKey) throws UtilsException{
		try{
			if(publicKey==null) {
				return null;
			}
			Enumeration<String> aliases = this.keystoreArchive.aliases();
			while (aliases.hasMoreElements()) {
				String alias = aliases.nextElement();
				Certificate cer = this.keystoreArchive.getCertificate(alias);
				PublicKey pk = cer.getPublicKey();
				if(pk!=null && pk.equals(publicKey)) {
					return cer;
				}
			}
			return null;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}	
	}
	public boolean existsCertificateByPublicKey(PublicKey publicKey) throws UtilsException{
		try{
			return this.getCertificateByPublicKey(publicKey)!=null;
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}	
	}
	
	public String getDigestMD5UrlEncoded(String alias) throws UtilsException{
		return this.getDigestUrlEncoded(alias, MessageDigestUtils.ALGO_MD5);
	}
	public String getDigestSHA1UrlEncoded(String alias) throws UtilsException{
		return this.getDigestUrlEncoded(alias, MessageDigestUtils.ALGO_SHA_1);
	}
	public String getDigestSHA256UrlEncoded(String alias) throws UtilsException{
		return this.getDigestUrlEncoded(alias, MessageDigestUtils.ALGO_SHA_256);
	}
	public String getDigestUrlEncoded(String alias, String digestAlgo) throws UtilsException{
		try{
			Certificate cer = getCertificate(alias);
			if(cer==null) {
				throw new UtilsException("Certificate '"+alias+"' not exists");
			}
			return this.buildDigestUrlEncoded(cer, digestAlgo);
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}	
	}
	private String buildDigestUrlEncoded(Certificate cer, String digestAlgo) throws UtilsException{
		try{
			byte[] digestB = MessageDigestUtils.createDigest(cer.getEncoded(), digestAlgo);
			return Base64UrlUtility.encode(digestB);
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}
	}
	
	public boolean existsAlias(String alias) throws UtilsException{
		try{
			return this.keystoreArchive.containsAlias(alias);
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}	
	}
	public Enumeration<String> aliases() throws UtilsException{
		try{
			return this.keystoreArchive.aliases();
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}
	}
	public PublicKey getPublicKey() throws UtilsException{
		return this.getCertificate().getPublicKey();
	}
	public PublicKey getPublicKey(String alias) throws UtilsException{
		return this.getCertificate(alias).getPublicKey();
	}
	
	public java.security.KeyStore getKeystore() {
		return this.keystoreArchive;
	}
	public boolean isKeystoreHsm() {
		return this.keystoreHsm;
	}
	public String getKeystoreType() {
		if(this.keystoreArchive==null) {
			return null;
		}
		return this.keystoreArchive.getType();
	}
	public java.security.Provider getKeystoreProvider() {
		return this.keystoreArchive.getProvider();
	}
	
	public void putCertificate(String alias, Certificate cert, boolean overwriteIfExists) throws UtilsException {
		if(this.existsAlias(alias)) {
			if(overwriteIfExists) {
				try {
					this.keystoreArchive.deleteEntry(alias);
				}catch(Exception t) {
					throw new UtilsException(t.getMessage(),t);
				}
			}
			else {
				return;
			}
		}
		try {
			this.keystoreArchive.setCertificateEntry(alias, cert);
		}catch(Exception t) {
			throw new UtilsException(t.getMessage(),t);
		}
	}
	public void putAllCertificate(KeyStore keystore, boolean overwriteIfExists) throws UtilsException {
		if(keystore!=null) {
			Enumeration<String> aliases = keystore.aliases();
			if(aliases!=null) {
				while (aliases.hasMoreElements()) {
					String alias = aliases.nextElement();
					Certificate cert = keystore.getCertificate(alias);
					putCertificate(alias, cert, overwriteIfExists);
				}
			}
		}
	}
	
}