View Javadoc

1   /**
2    * LICENCIA LGPL:
3    * 
4    * Esta librería es Software Libre; Usted puede redistribuirla y/o modificarla
5    * bajo los términos de la GNU Lesser General Public License (LGPL) tal y como 
6    * ha sido publicada por la Free Software Foundation; o bien la versión 2.1 de 
7    * la Licencia, o (a su elección) cualquier versión posterior.
8    * 
9    * Esta librería se distribuye con la esperanza de que sea útil, pero SIN 
10   * NINGUNA GARANTÍA; tampoco las implícitas garantías de MERCANTILIDAD o 
11   * ADECUACIÓN A UN PROPÓSITO PARTICULAR. Consulte la GNU Lesser General Public 
12   * License (LGPL) para más detalles
13   * 
14   * Usted debe recibir una copia de la GNU Lesser General Public License (LGPL) 
15   * junto con esta librería; si no es así, escriba a la Free Software Foundation 
16   * Inc. 51 Franklin Street, 5º Piso, Boston, MA 02110-1301, USA o consulte
17   * <http://www.gnu.org/licenses/>.
18   *
19   * Copyright 2011 Agencia de Tecnología y Certificación Electrónica
20   */
21  package es.accv.arangi.base.signature;
22  
23  import java.lang.reflect.InvocationTargetException;
24  import java.lang.reflect.Method;
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import org.apache.log4j.Logger;
29  
30  import es.accv.arangi.base.ArangiObject;
31  import es.accv.arangi.base.certificate.validation.CAList;
32  import es.accv.arangi.base.certificate.validation.CertificateValidationService;
33  import es.accv.arangi.base.document.IDocument;
34  import es.accv.arangi.base.exception.certificate.NormalizeCertificateException;
35  import es.accv.arangi.base.exception.document.HashingException;
36  import es.accv.arangi.base.exception.signature.NoDocumentToSignException;
37  import es.accv.arangi.base.exception.signature.SignatureClassNotFoundException;
38  import es.accv.arangi.base.exception.signature.SignatureException;
39  import es.accv.arangi.base.util.validation.ValidationResult;
40  
41  
42  /**
43   * Clase base para todas las implementaciones de {@link ISignature ISignature}
44   * 
45   * @author <a href="mailto:jgutierrez@accv.es">José M Gutiérrez</a>
46   */
47  public abstract class Signature extends ArangiObject implements ISignature{
48  
49  	/*
50  	 * Nombre de método que se buscará en los reconocedores
51  	 */
52  	private static final String RECOGNIZER_METHOD_NAME	= "getSignatureInstance";
53  	
54  	/*
55  	 * Logger de la clase
56  	 */
57  	static Logger logger = Logger.getLogger(Signature.class);
58  	
59  	/*
60  	 * Lista de clases que pueden reconocer una firma
61  	 */
62  	private static List<Class> recognizersList;
63  	
64  	/**
65  	 * Valida una firma attached mediante servicios de validación.
66  	 * 
67  	 * @param bSignature Firma como array de bytes
68  	 * @param validationServices Servicios de validación
69  	 * @return Resultado de la validación
70  	 * @throws SignatureClassNotFoundException Ninguna de las clases de firma de Arangí
71  	 *  es capaz de cargar la firma pasada como parámetro 
72  	 * @throws HashingException Error obteniendo el hash del documento
73  	 * @throws SignatureException Error tratando el objeto firma
74  	 * @throws NormalizeCertificateException Alguno de los certificados no puede ser 
75  	 * 	normalizado al formato reconocido por el proveedor criptográfico de Arangí o su 
76  	 * 	firma no es correcta o no puede ser analizada
77  	 * @throws NoDocumentToSignException La firma no es attached por lo que no hay documento con
78  	 * 	el que validarla. Utilizar este mismo método pero pasándole el documento que originó la
79  	 * 	firma
80  	 */
81  	public static ValidationResult[] validateSignature (byte[] bSignature, List<CertificateValidationService> validationServices) throws SignatureClassNotFoundException, HashingException, SignatureException, NormalizeCertificateException, NoDocumentToSignException {
82  		logger.debug("[Signature.validateSignature]::Entrada");
83  		
84  		ISignature signature = getSignatureObject (bSignature);
85  		return signature.isValid(validationServices);
86  	}
87  	
88  	/**
89  	 * Valida una firma attached mediante una lista de certificados de Autoridades de
90  	 * Certificación.
91  	 * 
92  	 * @param bSignature Firma como array de bytes
93  	 * @param caList Lista de certificados de CA
94  	 * @return Resultado de la validación
95  	 * @throws SignatureClassNotFoundException Ninguna de las clases de firma de Arangí
96  	 *  es capaz de cargar la firma pasada como parámetro 
97  	 * @throws HashingException Error obteniendo el hash del documento
98  	 * @throws SignatureException Error tratando el objeto firma
99  	 * @throws NormalizeCertificateException Alguno de los certificados no puede ser 
100 	 * 	normalizado al formato reconocido por el proveedor criptográfico de Arangí o su 
101 	 * 	firma no es correcta o no puede ser analizada
102 	 * @throws NoDocumentToSignException La firma no es attached por lo que no hay documento con
103 	 * 	el que validarla. Utilizar este mismo método pero pasándole el documento que originó la
104 	 * 	firma
105 	 */
106 	public static ValidationResult[] validateSignature (byte[] bSignature, CAList caList) throws SignatureClassNotFoundException, HashingException, SignatureException, NormalizeCertificateException, NoDocumentToSignException {
107 		logger.debug("[Signature.validateSignature]::Entrada");
108 		
109 		ISignature signature = getSignatureObject (bSignature);
110 		return signature.isValid(caList);
111 	}
112 	
113 	/**
114 	 * Valida una firma attached mediante servicios de validación y, si no puede
115 	 * conseguirlo prueba con una lista de certificados de Autoridades de
116 	 * Certificación.
117 	 * 
118 	 * @param bSignature Firma como array de bytes
119 	 * @param validationServices Servicios de validación
120 	 * @param caList Lista de certificados de CA
121 	 * @return Resultado de la validación
122 	 * @throws SignatureClassNotFoundException Ninguna de las clases de firma de Arangí
123 	 *  es capaz de cargar la firma pasada como parámetro 
124 	 * @throws HashingException Error obteniendo el hash del documento
125 	 * @throws SignatureException Error tratando el objeto firma
126 	 * @throws NormalizeCertificateException Alguno de los certificados no puede ser 
127 	 * 	normalizado al formato reconocido por el proveedor criptográfico de Arangí o su 
128 	 * 	firma no es correcta o no puede ser analizada
129 	 * @throws NoDocumentToSignException La firma no es attached por lo que no hay documento con
130 	 * 	el que validarla. Utilizar este mismo método pero pasándole el documento que originó la
131 	 * 	firma
132 	 */
133 	public static ValidationResult[] validateSignature (byte[] bSignature, List<CertificateValidationService> validationServices, CAList caList) throws SignatureClassNotFoundException, HashingException, SignatureException, NormalizeCertificateException, NoDocumentToSignException {
134 		logger.debug("[Signature.validateSignature]::Entrada");
135 		
136 		ISignature signature = getSignatureObject (bSignature);
137 		ValidationResult[] result = null;
138 		try {
139 			result = signature.isValid(caList);
140 		} catch (Exception e) {
141 			logger.debug("[Signature.validateSignature]::No se ha podido validar CAList, probamos con servicios de validación");
142 		}
143 		
144 		boolean validarConServicios = false;
145 		if (result == null) {
146 			validarConServicios = true;
147 		} else {
148 			for (int i = 0; i < result.length; i++) {
149 				if (result[i].getResult() == ValidationResult.RESULT_CERTIFICATE_NOT_BELONGS_TRUSTED_CAS) {
150 					validarConServicios = true;
151 				}
152 			}
153 		}
154 		
155 		if (!validarConServicios) {
156 			return result;
157 		} else {
158 			return signature.isValid(validationServices);
159 		}
160 	}
161 	
162 	/**
163 	 * Valida una firma detached mediante servicios de validación.
164 	 * 
165 	 * @param document Archivo que generó la firma
166 	 * @param bSignature Firma como array de bytes
167 	 * @param validationServices Servicios de validación
168 	 * @return Resultado de la validación
169 	 * @throws SignatureClassNotFoundException Ninguna de las clases de firma de Arangí
170 	 *  es capaz de cargar la firma pasada como parámetro 
171 	 * @throws HashingException Error obteniendo el hash del documento
172 	 * @throws SignatureException Error tratando el objeto firma
173 	 * @throws NormalizeCertificateException Alguno de los certificados no puede ser 
174 	 * 	normalizado al formato reconocido por el proveedor criptográfico de Arangí o su 
175 	 * 	firma no es correcta o no puede ser analizada
176 	 */
177 	public static ValidationResult[] validateSignature (IDocument document, byte[] bSignature, List<CertificateValidationService> validationServices) throws SignatureClassNotFoundException, HashingException, SignatureException, NormalizeCertificateException {
178 		logger.debug("[Signature.validateSignature]::Entrada");
179 		
180 		ISignature signature = getSignatureObject (bSignature);
181 		return signature.isValid(document, validationServices);
182 	}
183 	
184 	/**
185 	 * Valida una firma detached mediante una lista de certificados de Autoridades de
186 	 * Certificación.
187 	 * 
188 	 * @param document Archivo que generó la firma
189 	 * @param bSignature Firma como array de bytes
190 	 * @param caList Lista de certificados de CA
191 	 * @return Resultado de la validación
192 	 * @throws SignatureClassNotFoundException Ninguna de las clases de firma de Arangí
193 	 *  es capaz de cargar la firma pasada como parámetro 
194 	 * @throws HashingException Error obteniendo el hash del documento
195 	 * @throws SignatureException Error tratando el objeto firma
196 	 * @throws NormalizeCertificateException Alguno de los certificados no puede ser 
197 	 * 	normalizado al formato reconocido por el proveedor criptográfico de Arangí o su 
198 	 * 	firma no es correcta o no puede ser analizada
199 	 */
200 	public static ValidationResult[] validateSignature (IDocument document, byte[] bSignature, CAList caList) throws SignatureClassNotFoundException, HashingException, SignatureException, NormalizeCertificateException {
201 		logger.debug("[Signature.validateSignature]::Entrada");
202 		
203 		ISignature signature = getSignatureObject (bSignature);
204 		return signature.isValid(document, caList);
205 	}
206 	
207 	/**
208 	 * Valida una firma detached mediante servicios de validación y, si no puede
209 	 * conseguirlo prueba con una lista de certificados de Autoridades de
210 	 * Certificación.
211 	 * 
212 	 * @param document Archivo que generó la firma
213 	 * @param bSignature Firma como array de bytes
214 	 * @param validationServices Servicios de validación
215 	 * @param caList Lista de certificados de CA
216 	 * @return Resultado de la validación
217 	 * @throws SignatureClassNotFoundException Ninguna de las clases de firma de Arangí
218 	 *  es capaz de cargar la firma pasada como parámetro 
219 	 * @throws HashingException Error obteniendo el hash del documento
220 	 * @throws SignatureException Error tratando el objeto firma
221 	 * @throws NormalizeCertificateException Alguno de los certificados no puede ser 
222 	 * 	normalizado al formato reconocido por el proveedor criptográfico de Arangí o su 
223 	 * 	firma no es correcta o no puede ser analizada
224 	 */
225 	public static ValidationResult[] validateSignature (IDocument document, byte[] bSignature, List<CertificateValidationService> validationServices, CAList caList) throws SignatureClassNotFoundException, HashingException, SignatureException, NormalizeCertificateException {
226 		logger.debug("[Signature.validateSignature]::Entrada");
227 		
228 		ISignature signature = getSignatureObject (bSignature);
229 		try {
230 			ValidationResult[] result = signature.isValid(document, caList);
231 			boolean unknownCertificates = false;
232 			for (int i = 0; i < result.length; i++) {
233 				if (result[i].getResult() == ValidationResult.RESULT_CERTIFICATE_UNKNOWN ||
234 						result[i].getResult() == ValidationResult.RESULT_CERTIFICATE_CANNOT_BE_VALIDATED) {
235 					unknownCertificates = true;
236 					break;
237 				}
238 			}
239 			if (!unknownCertificates) {
240 				return result;
241 			}
242 		} catch (Exception e) {
243 			logger.debug("[Signature.validateSignature]::No se ha podido validar con CAList, probamos con servicios de validación");
244 		}
245 		
246 		//-- Si estamos aquí es porque no se ha podido validar con CAList, probamos con servicios de validación
247 		return signature.isValid(document, validationServices);
248 	}
249 	
250 	/**
251 	 * Valida una firma attached sin validar los certificados.
252 	 * 
253 	 * @param bSignature Firma como array de bytes
254 	 * @return Resultado de la validación
255 	 * @throws SignatureClassNotFoundException Ninguna de las clases de firma de Arangí
256 	 *  es capaz de cargar la firma pasada como parámetro 
257 	 * @throws HashingException Error obteniendo el hash del documento
258 	 * @throws SignatureException Error tratando el objeto firma
259 	 * @throws NoDocumentToSignException La firma no es attached por lo que no hay documento con
260 	 * 	el que validarla. Utilizar este mismo método pero pasándole el documento que originó la
261 	 * 	firma
262 	 */
263 	public static ValidationResult[] validateSignatureOnly (byte[] bSignature) throws SignatureClassNotFoundException, HashingException, SignatureException, NoDocumentToSignException {
264 		logger.debug("[Signature.validateSignatureOnly]::Entrada");
265 		
266 		ISignature signature = getSignatureObject (bSignature);
267 		return signature.isValidSignatureOnly();
268 	}
269 	
270 	/**
271 	 * Valida una firma detached sin validar los certificados.
272 	 * 
273 	 * @param document Archivo que generó la firma
274 	 * @param bSignature Firma como array de bytes
275 	 * @return Resultado de la validación
276 	 * @throws SignatureClassNotFoundException Ninguna de las clases de firma de Arangí
277 	 *  es capaz de cargar la firma pasada como parámetro 
278 	 * @throws HashingException Error obteniendo el hash del documento
279 	 * @throws SignatureException Error tratando el objeto firma
280 	 * @throws NoDocumentToSignException La firma no es attached por lo que no hay documento con
281 	 * 	el que validarla. Utilizar este mismo método pero pasándole el documento que originó la
282 	 * 	firma
283 	 */
284 	public static ValidationResult[] validateSignatureOnly (IDocument document, byte[] bSignature) throws SignatureClassNotFoundException, HashingException, SignatureException, NoDocumentToSignException {
285 		logger.debug("[Signature.validateSignatureOnly]::Entrada");
286 		
287 		ISignature signature = getSignatureObject (bSignature);
288 		return signature.isValidSignatureOnly(document);
289 	}
290 	
291 	/**
292 	 * Añade una nueva clase que permite reconocer tipos de firma. La nueva clase
293 	 * deberá contener un método estático 'getSignatureInstance'.
294 	 * 
295 	 * @param recognizerClass Clase que reconoce un tipo de firma
296 	 */
297 	public static void addRecognizerClass (Class recognizerClass) {
298 		List<Class> recognizerClasses = getRecognizersList();
299 		if (!recognizerClasses.contains(recognizerClass)) {
300 			recognizerClasses.add(recognizerClass);
301 		}
302 	}
303 
304 	/**
305 	 * Obtiene el tipo de la firma que se pasa como parámetro.
306 	 * 
307 	 * @param bSignature Contenido de la firma como array de bytes
308 	 * @return tipo de la firma
309 	 * @throws SignatureClassNotFoundException Ninguna de las clases de firma de Arangí
310 	 *  es capaz de cargar la firma pasada como parámetro 
311 	 */
312 	public static String getType (byte[] bSignature) throws SignatureClassNotFoundException {
313 		logger.debug("[Signature.getSignatureType]::Entrada");
314 		
315 		ISignature signature = getSignatureObject(bSignature);
316 		return signature.getSignatureType();
317 	}
318 	
319 	/**
320 	 * Obtiene un objeto de tipo ISignature para tratar la firma pasada
321 	 * como parámetro.
322 	 * 
323 	 * @param bSignature Contenido de la firma como array de bytes
324 	 * @return Objeto firma
325 	 * @throws SignatureClassNotFoundException Ninguna de las clases de firma de Arangí
326 	 *  es capaz de cargar la firma pasada como parámetro 
327 	 */
328 	public static ISignature getSignatureObject (byte[] bSignature) throws SignatureClassNotFoundException {
329 		logger.debug("[Signature.getSignatureObject]::Entrada");
330 		
331 		//-- Recorrer la lista de reconocedores
332 		for(Class recognizerClass : getRecognizersList()) {
333 			logger.debug("[Signature.getSignatureObject]::Probar con la clase: " + recognizerClass);
334 			Method method;
335 			try {
336 				method = recognizerClass.getMethod(RECOGNIZER_METHOD_NAME,new Class[] { byte[].class });
337 			} catch (SecurityException e1) {
338 				logger.info("[Signature.getSignatureObject]::Excepción de seguridad al llamar al método getSignatureInstance de la clase: " + recognizerClass);
339 				continue;
340 			} catch (NoSuchMethodException e1) {
341 				logger.info("[Signature.getSignatureObject]::El método getSignatureInstance no existe en la clase: " + recognizerClass);
342 				continue;
343 			}
344 			try {
345 				return (ISignature) method.invoke(null, new Object[] { bSignature });
346 			} catch (IllegalArgumentException e) {
347 				logger.info("[Signature.getSignatureObject]::El método getSignatureInstance existe pero con parámetros equivocados en la clase: " + recognizerClass);
348 				continue;
349 			} catch (IllegalAccessException e) {
350 				logger.info("[Signature.getSignatureObject]::Acceso ilegal al llamar al método getSignatureInstance de la clase: " + recognizerClass);
351 				continue;
352 			} catch (InvocationTargetException e) {
353 				logger.debug("[Signature.getSignatureObject]::La firma no es del tipo que trata: " + recognizerClass);
354 				continue;
355 			}
356 		}
357 		
358 		throw new SignatureClassNotFoundException("No se ha encontrado ninguna clase para tratar la firma");
359 	}
360 	
361 	//-- Métodos privados
362 	
363 	/*
364 	 * Obtiene la lista de clases reconocedoras de firma
365 	 */
366 	private static List<Class> getRecognizersList () {
367 		if (recognizersList == null) {
368 			//-- Añadir los tipos tratados por Arangí
369 			recognizersList = new ArrayList<Class>();
370 			recognizersList.add(XAdESSignature.class);
371 			recognizersList.add(BasePDFSignature.class);
372 			recognizersList.add(CMSPKCS7Signature.class);
373 		}
374 		
375 		return recognizersList;
376 	}
377 	
378 }