CRLCertstore.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.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.security.cert.CertStore;
import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.X509CRL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.openspcoop2.utils.Utilities;
import org.openspcoop2.utils.UtilsException;

/**
 * CRLCertstore
 *
 * @author Andrea Poli (apoli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */
public class CRLCertstore implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private List<byte []> crlBytes = null;
	private List<String> crlPaths = null;
	
	private transient CertificateFactory certFactory = null;
	private transient List<X509CRL> caCrls = null;
	private transient CertStore certStore = null;
	
	@Override
	public String toString() {
		StringBuilder bf = new StringBuilder();
		bf.append("CRLCertstore (");
		boolean first = true;
		if(this.crlPaths!=null) {
			for (String crlPath : this.crlPaths) {
				if(!first) {
					bf.append(", ");
				}
				bf.append(crlPath);	
				first=false;
			}
		}
		else {
			bf.append("Nessuna crl definita");
		}
		bf.append(")");
		return bf.toString();
	}
	
	public static List<String> readCrlPaths(String crlPaths){
		List<String> crlPathsList = new ArrayList<>();
		if(crlPaths!=null && StringUtils.isNotEmpty(crlPaths)) {
			if(crlPaths.contains(",")) {
				String [] tmp = crlPaths.split(",");
				for (String crlPath : tmp) {
					crlPathsList.add(crlPath.trim());
				}
			}
			else {
				crlPathsList.add(crlPaths.trim());
			}
		}
		return crlPathsList;
	}
	
	public static String convertToCrlPaths(List<String> crlPathsList) {
		StringBuilder sb = new StringBuilder();
		if(crlPathsList==null || crlPathsList.isEmpty()) {
			return null;
		}
		for (String path : crlPathsList) {
			if(sb.length()>0) {
				sb.append(",");
			}
			sb.append(path);
		}
		return sb.toString();
	}
	
	public CRLCertstore(String crlPaths) throws UtilsException {
		this(crlPaths, null);
	}
	public CRLCertstore(String crlPaths, Map<String, byte[]> localResources) throws UtilsException {
		List<String> crlPathsList = readCrlPaths(crlPaths);
		this.initEngine(crlPathsList, localResources);
	}
	
	public CRLCertstore(List<String> crlPaths) throws UtilsException{
		this(crlPaths, null);
	}
	public CRLCertstore(List<String> crlPaths, Map<String, byte[]> localResources) throws UtilsException{
		this.initEngine(crlPaths, localResources);
	}
	
	private void initEngine(List<String> crlPaths, Map<String, byte[]> localResources) throws UtilsException{
		
		try{
			if(crlPaths==null || crlPaths.isEmpty()){
				throw new UtilsException("crlPaths non indicato");
			}
		
			this.crlPaths = crlPaths;
			this.crlBytes = new ArrayList<>();
			
			for (String crlPath : crlPaths) {

				if(localResources!=null && !localResources.isEmpty() && localResources.containsKey(crlPath)) {
					
					byte[] r = localResources.get(crlPath);
					if(r!=null && r.length>0) {
						this.crlBytes.add(r);
					}
					
					continue;
				}
				
				initEngineCrl(crlPath);
			}
			

			this.initCRL();
			
		}catch(Exception e){
			throw new UtilsException(e.getMessage(),e);
		}
		
	}
	private void initEngineCrl(String crlPath) throws UtilsException, IOException {
		
		byte[] crlBytesAdd = null;
		File fStore = new File(crlPath);
		boolean fStoreExists = fStore.exists();
		try(InputStream isStore = fStoreExists ? new FileInputStream(fStore) : CRLCertstore.class.getResourceAsStream(crlPath);){
			if(isStore!=null) {
				crlBytesAdd = Utilities.getAsByteArray(isStore);
			}
		}
		if(crlBytesAdd==null && !fStoreExists) {
			try(InputStream isStore = CRLCertstore.class.getResourceAsStream("/"+crlPath);){
				if(isStore!=null) {
					crlBytesAdd = Utilities.getAsByteArray(isStore);
				}
			}
		}
		if(crlBytesAdd==null) {
			throw new UtilsException("Store ["+crlPath+"] not found");
		}
		this.crlBytes.add(crlBytesAdd);
	}
	
	
	private void checkInit() throws UtilsException{
		if(this.caCrls==null) {
			this.initCRL();
		}
	}
	private synchronized void initCRL() throws UtilsException{
		if(this.caCrls==null) {
			
			// create a X509 certificate factory for later use
			try {
				this.certFactory = org.openspcoop2.utils.certificate.CertificateFactory.getCertificateFactory();
			}catch(Exception e){
				throw new UtilsException("Error getInstance CertificateFactory: "+e.getMessage(),e);
			}
			
			this.caCrls = new ArrayList<>();
			for (int i = 0; i < this.crlBytes.size(); i++) {
				byte [] crl = this.crlBytes.get(i);
				try(ByteArrayInputStream bin = new ByteArrayInputStream(crl)){
					X509CRL caCrl = (X509CRL) this.certFactory.generateCRL(bin); 
					this.caCrls.add(caCrl);
				}
				catch(Exception e){
					throw new UtilsException("Error loading CRL '"+this.crlPaths.get(i)+"': "+e.getMessage(),e);
				}
			}
			
			try {
				CollectionCertStoreParameters certStoreParams =
			                new CollectionCertStoreParameters(this.caCrls);
				this.certStore =
			                CertStore.getInstance("Collection", certStoreParams);
			}catch(Exception e){
				throw new UtilsException("Build CertStore failed: "+e.getMessage(),e);
			}
		}
	}
	

	public CertificateFactory getCertFactory() throws UtilsException {
		this.checkInit(); // per ripristino da Serializable
		return this.certFactory;
	}

	public List<X509CRL> getCaCrls() throws UtilsException {
		this.checkInit(); // per ripristino da Serializable
		return this.caCrls;
	}

	public CertStore getCertStore() throws UtilsException {
		this.checkInit(); // per ripristino da Serializable
		return this.certStore;
	}
	
	public int countCrls() {
		return this.crlBytes!=null ? this.crlBytes.size() : 0;
	}
	
}