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.certificate.validation;
22  
23  import java.io.File;
24  import java.io.FileNotFoundException;
25  import java.io.InputStream;
26  import java.net.URL;
27  import java.security.cert.X509Certificate;
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.Date;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.StringTokenizer;
34  
35  import org.apache.log4j.Logger;
36  
37  import es.accv.arangi.base.certificate.Certificate;
38  import es.accv.arangi.base.exception.certificate.CertificateCANotFoundException;
39  import es.accv.arangi.base.exception.certificate.CertificateFieldException;
40  import es.accv.arangi.base.exception.certificate.InvalidCRLException;
41  import es.accv.arangi.base.exception.certificate.NormalizeCertificateException;
42  import es.accv.arangi.base.util.validation.ValidationResult;
43  
44  /**
45   * Clase que añade la funcionalidad de validación a la clase 
46   * {@link es.accv.arangi.base.certificate.Certificate Certificate}.<br><br>
47   * 
48   * Para realizar la validación se siguen los siguientes pasos:<br>
49   * 
50   * <ol>
51   * 	<li>Si el certificado no está dentro de su periodo de validez no es válido.</li>
52   * 	<li>Si el certificado está autofirmado es válido.</li>
53   * 	<li>Si el objeto {@link CAList CAList} contiene un fichero de validación XML 
54   * 		({@link ValidationXML ValidationXML}) se comprueba si la Autoridad de 
55   * 		Certificación (CA) emisora existe en él. Si es así se valida contra el OCSP 
56   * 		y/o la CRL que se indiquen. De esta forma obtendremos si el certificado es 
57   * 		válido o no.</li>
58   * 	<li>Si el certificado tiene extensión Authority Information Access (AIA) y en ella
59   * 		hay definido uno o varios OCSP, se realiza la validación contra él/ellos.</li>
60   * 	<li>Si el certificado tiene extensión CRL Distribution Point, se realiza la 
61   * 		validación contra la CRL en él definida.</li>
62   * 	<li>Si se llega a este paso sin haber podido realizar la validación se devolverá
63   * 		un resultado indicando que el certificado no se puede validar.</li>
64   * 	<li>Si el certificado ha resultado válido, se validarán los certificados que forman 
65   * 		parte de su cadena de confianza siguiendo los pasos anteriores. Si alguno de
66   * 		ellos resulta no válido se devolverá un resultado indicando que la cadena de
67   * 		confianza del certificado no es válida.</li>
68   * </ol><br><br>
69   * 
70   * El objeto {@link CAList CAList} con el que se inicializa esta clase es fundamental
71   * durante el proceso de validación. Además de la función ya indicada de poder contener
72   * un fichero de validación XML, la lista de certificados de CA que contiene permite a
73   * esta clase obtener la cadena de confianza de los certificados a validar. De esta forma
74   * también es posible controlar cuáles son las CAs con las que se va a trabajar, no 
75   * permitiendo que se validen en el sistema certificados de los que se desconoce su
76   * procedencia.<br><br>
77   * 
78   * Un ejemplo de uso de esta clase sería:<br><br>
79   * 
80   * <code>
81   * 	CAList caList = new CAList (new File ("c:/certificates/caCertificates"));<br>
82   * 	X509Certificate certificate = Util.getCertificate(new File ("c:/certificates/myCertificate.cer"));<br>
83   *  ValidateCertificate validateCertificate = new ValidateCertificate (certificate, caList);<br>
84   * 	int result = validateCertificate.validate ();<br>
85   * 	System.out.println ("Válido Hoy?: " + CertificateValidator.getString (result));<br><br>
86   * 	
87   * 	// validación histórica
88   * 	SimpleDateFormat dateFormat = new SimpleDateFormat ("dd/MM/yyyy");
89   * 	result = validateCertificate.validate (dateFormat.parse ("01/01/2008"));
90   * 	System.out.println ("Válido el 01/01/2008?: " + CertificateValidator.getString (result));<br><br>
91   * </code>
92   * 
93   * La mayoría de Autoridades de Certificación eliminan la información de revocación
94   * de los certificados caducados de sus CRLs. En estos casos la validación histórica no
95   * es posible y Arangi devolverá que el certificado era válido, ya que tanto la CRL como
96   * el OCSP devuelven este resultado. La única forma de realizar validación histórica sería 
97   * dentro de un proceso de firma longeva.
98   * 
99   * @author <a href="mailto:jgutierrez@accv.es">José M Gutiérrez</a>
100  */
101 public class ValidateCertificate extends Certificate {
102 	
103 	/*
104 	 * Class logger
105 	 */
106 	private static Logger logger = Logger.getLogger(ValidateCertificate.class);
107 	
108 	/*
109 	 * Certificate that this object envelopes
110 	 */
111 	private X509Certificate issuerCertificate;
112 	
113 	/*
114 	 * List of CA certificates
115 	 */
116 	CAList caList;
117 
118 	/*
119 	 * Validation XML
120 	 */
121 	ValidationXML validationXML;
122 	
123 	/*
124 	 * Trace object
125 	 */
126 	ValidatingTrace trace = new ValidatingTrace();
127 	
128 	/*
129 	 * OCSP
130 	 */
131 	OCSPClient ocsp;
132 
133 	/*
134 	 * CRL
135 	 */
136 	CRL crl;
137 	
138 	//-- Constructor
139 	
140 	/**
141 	 * Constructor en base a un objeto java.security.cert.X509Certificate.
142 	 * 
143 	 * @param certificate Certificado X.509 v3
144 	 * @param caList Lista de certificados de CA
145 	 * 
146 	 * @throws CertificateCANotFoundException El certificado no pertenece a ninguna CA conocida
147 	 * @throws NormalizeCertificateException El certificado no puede ser normalizado al formato
148 	 * 	reconocido por el proveedor criptográfico de Arangi o su firma no es correcta o no
149 	 * 	puede ser analizada
150 	 */
151 	public ValidateCertificate(X509Certificate certificate, CAList caList) throws CertificateCANotFoundException, NormalizeCertificateException{
152 		super (certificate);
153 		initialize (caList, null, null, null);
154 	}
155 	
156 	/**
157 	 * Constructor en base a un fichero.
158 	 * 
159 	 * @param fileCertificate Fichero que contiene el certificado (tal cual o en formato PEM).
160 	 * @param caList Lista de certificados de CA
161 	 * 
162 	 * @throws CertificateCANotFoundException El certificado no pertenece a ninguna CA conocida
163 	 * @throws NormalizeCertificateException El certificado no puede ser normalizado al formato
164 	 * 	reconocido por el proveedor criptográfico de Arangi o su firma no es correcta o no
165 	 * 	puede ser analizada
166 	 * @throws FileNotFoundException El fichero no existe
167 	 */
168 	public ValidateCertificate(File fileCertificate, CAList caList) throws CertificateCANotFoundException, NormalizeCertificateException, FileNotFoundException{
169 		super (fileCertificate);
170 		initialize (caList, null, null, null);
171 	}
172 	
173 	/**
174 	 * Constructor en base a un stream de lectura.
175 	 * 
176 	 * @param is Stream de lectura que contiene el certificado (tal cual o en formato PEM).
177 	 * @param caList Lista de certificados de CA
178 	 * 
179 	 * @throws CertificateCANotFoundException El certificado no pertenece a ninguna CA conocida
180 	 * @throws NormalizeCertificateException El certificado no puede ser normalizado al formato
181 	 * 	reconocido por el proveedor criptográfico de Arangi o su firma no es correcta o no
182 	 * 	puede ser analizada
183 	 */
184 	public ValidateCertificate(InputStream is, CAList caList) throws CertificateCANotFoundException, NormalizeCertificateException{
185 		super (is);
186 		initialize (caList, null, null, null);
187 	}
188 	
189 	/**
190 	 * Constructor en base a un array de bytes.
191 	 * 
192 	 * @param contenidoCertificado Array de bytes que es el contenido del certificado (tal cual o en formato PEM).
193 	 * @param caList Lista de certificados de CA
194 	 * 
195 	 * @throws CertificateCANotFoundException El certificado no pertenece a ninguna CA conocida
196 	 * @throws NormalizeCertificateException El certificado no puede ser normalizado al formato
197 	 * 	reconocido por el proveedor criptográfico de Arangi o su firma no es correcta o no
198 	 * 	puede ser analizada
199 	 */
200 	public ValidateCertificate(byte[] contenidoCertificado, CAList caList) throws CertificateCANotFoundException, NormalizeCertificateException{
201 		super (contenidoCertificado);
202 		initialize (caList, null, null, null);
203 	}
204 	
205 	/**
206 	 * Constructor en base a un objeto java.security.cert.X509Certificate que permite obtener
207 	 * la traza de validación.
208 	 * 
209 	 * @param certificate Certificado X.509 v3
210 	 * @param caList Lista de certificados de CA
211 	 * @param trace Traza de los pasos dados durante la validación
212 	 * 
213 	 * @throws CertificateCANotFoundException El certificado no pertenece a ninguna CA conocida
214 	 * @throws NormalizeCertificateException El certificado no puede ser normalizado al formato
215 	 * 	reconocido por el proveedor criptográfico de Arangi o su firma no es correcta o no
216 	 * 	puede ser analizada
217 	 */
218 	public ValidateCertificate(X509Certificate certificate, CAList caList, ValidatingTrace trace) throws CertificateCANotFoundException, NormalizeCertificateException{
219 		super (certificate);
220 		initialize (caList, null, null, trace);
221 
222 	}
223 	
224 	/**
225 	 * Constructor en base a un objeto java.security.cert.X509Certificate. Se le puede
226 	 * indicar el OCSP y/o la CRL que se utilizan para realizar la validación. Este
227 	 * constructor es interesante para realizar validaciones de certificados de CA,
228 	 * que en muchas ocasiones no contienen información de validación.
229 	 * 
230 	 * @param certificate Certificado X.509 v3
231 	 * @param caList Lista de certificados de CA
232 	 * @param ocsp Cliente OCSP donde realizar la validación (puede ser nulo)
233 	 * @param crl CRL donde realizar la validación (puede ser nula)
234 	 * 
235 	 * @throws CertificateCANotFoundException El certificado no pertenece a ninguna CA conocida
236 	 * @throws NormalizeCertificateException El certificado no puede ser normalizado al formato
237 	 * 	reconocido por el proveedor criptográfico de Arangi o su firma no es correcta o no
238 	 * 	puede ser analizada
239 	 */
240 	public ValidateCertificate(X509Certificate certificate, CAList caList, OCSPClient ocsp, CRL crl) throws CertificateCANotFoundException, NormalizeCertificateException{
241 		super (certificate);
242 		initialize (caList, ocsp, crl, null);
243 	}
244 	
245 	/**
246 	 * Constructor en base a un objeto java.security.cert.X509Certificate que permite obtener
247 	 * la traza de validación. Se le puede indicar el OCSP y/o la CRL que se utilizan para 
248 	 * realizar la validación. Este constructor es interesante para realizar validaciones de 
249 	 * certificados de CA, que en muchas ocasiones no contienen información de validación.
250 	 * 
251 	 * @param certificate Certificado X.509 v3
252 	 * @param caList Lista de certificados de CA
253 	 * @param ocsp Cliente OCSP donde realizar la validación (puede ser nulo)
254 	 * @param crl CRL donde realizar la validación (puede ser nula)
255 	 * @param trace Traza de los pasos dados durante la validación
256 	 * 
257 	 * @throws CertificateCANotFoundException El certificado no pertenece a ninguna CA conocida
258 	 * @throws NormalizeCertificateException El certificado no puede ser normalizado al formato
259 	 * 	reconocido por el proveedor criptográfico de Arangi o su firma no es correcta o no
260 	 * 	puede ser analizada
261 	 */
262 	public ValidateCertificate(X509Certificate certificate, CAList caList, OCSPClient ocsp, CRL crl, ValidatingTrace trace) throws CertificateCANotFoundException, NormalizeCertificateException{
263 		super(certificate);
264 		initialize (caList, ocsp, crl, null);
265 	}
266 	
267 	/**
268 	 * Devuelve la lista de certificados de CA que requiere este certificado
269 	 * 
270 	 * @return lista de certificados de CA que requiere este certificado
271 	 */
272 	public CAList getCertificationChainAsCAList () {
273 		ValidateCertificate[] arrayCertificates = getCertificationChain();
274 		CAList caList = new CAList();
275 		for (int i = 0; i < arrayCertificates.length; i++) {
276 			caList.addCACertificate(arrayCertificates[i].toX509Certificate());
277 		}
278 		
279 		return caList;
280 	}
281 	
282 	/**
283 	 * Valida el certificado y su cadena de confianza.
284 	 * 
285 	 * @return Resultado de la validación según las constantes definidas en {@link CertificateValidator CertificateValidator}
286 	 */
287 	public int validate () {
288 		this.trace = new ValidatingTrace();
289 		return validate (this.trace);
290 	}
291 	
292 	/**
293 	 * Valida el certificado y su cadena de confianza en un momento del tiempo. Hay que 
294 	 * tener en cuenta lo indicado en la introducción de esta clase sobre la validación 
295 	 * histórica.
296 	 * 
297 	 * @param validationDate Fecha donde se evaluará la validación
298 	 * @return Resultado de la validación según las constantes definidas en {@link CertificateValidator CertificateValidator}
299 	 */
300 	public int validate (Date validationDate) {
301 		this.trace = new ValidatingTrace();
302 		return validate (validationDate, this.trace);
303 	}
304 	
305 	/**
306 	 * Valida el certificado y su cadena de confianza, permitiendo obtener la traza de 
307 	 * la validación.
308 	 * 
309 	 * @param externalTrace Traza de los pasos dados durante la validación
310 	 * @return Resultado de la validación según las constantes definidas en {@link CertificateValidator CertificateValidator}
311 	 */
312 	public int validate (ValidatingTrace externalTrace) {
313 		this.trace = externalTrace;
314 		return validate (new Date(), this.trace);
315 	}
316 		
317 	/**
318 	 * Valida el certificado y su cadena de confianza en un momento del tiempo, permitiendo 
319 	 * obtener la traza de la validación. Hay que tener en cuenta lo indicado en la 
320 	 * introducción de esta clase sobre la validación histórica.
321 	 * 
322 	 * @param validationDate Fecha donde se evaluará la validación
323 	 * @param externalTrace Traza de los pasos dados durante la validación
324 	 * @return Resultado de la validación según las constantes definidas en {@link CertificateValidator CertificateValidator}
325 	 */
326 	public int validate (Date validationDate, ValidatingTrace externalTrace) {
327 		
328 		logger.debug ("[ValidateCertificate.validate] :: Start :: " + Arrays.asList(new Object[] { validationDate, externalTrace }));
329 		
330 		//-- Load trace
331 		this.trace = externalTrace;
332 		if (this.trace == null) { this.trace = new ValidatingTrace(); }
333 		
334 		//-- If certificate is self signed return valid certificate
335 		try {
336 			if (isSelfSigned()) {
337 				//-- Check if the certificate has expired
338 				if (certificate.getNotBefore().after(validationDate)) {
339 					logger.debug ("[ValidateCertificate.validate] :: Certificate with subject DN=" + certificate.getSubjectDN().toString() + 
340 						" will not active until " + dateFormat.format(certificate.getNotBefore()) + ".");
341 					trace.add(certificate, "Certificate will not active until " + dateFormat.format(certificate.getNotBefore()));
342 					return ValidationResult.RESULT_CERTIFICATE_NOT_ACTIVE;
343 				}
344 				if (certificate.getNotAfter().before(validationDate)) {
345 					logger.debug ("[ValidateCertificate.validate] :: Certificate with subject DN=" + certificate.getSubjectDN().toString() + 
346 						" has expired in " + dateFormat.format(certificate.getNotBefore()) + ".");
347 					trace.add(certificate, "Certificate has expired in " + dateFormat.format(certificate.getNotBefore()));
348 					return ValidationResult.RESULT_CERTIFICATE_NOT_ACTIVE;
349 				}
350 				
351 				logger.debug ("[ValidateCertificate.validate] :: Certificate with subject DN=" + certificate.getSubjectDN().toString() +  
352 						" is valid and self signed. End of validation process.");
353 				trace.add(certificate, "Certificate is self signed, end of chain validation ");
354 				return ValidationResult.RESULT_VALID;
355 			}
356 		} catch (NormalizeCertificateException e1) {
357 			// Esta excepción ya se habrá dado en la inicialización, por lo que no se habría iniciado este objeto
358 		}
359 		
360 		//-- Validate certificate
361 		int result = validateCertificate (validationDate);
362 		if (result != ValidationResult.RESULT_VALID) {
363 			//-- Result not valid
364 			logger.debug ("[ValidateCertificate.validate] :: Certificate with subject DN=" + certificate.getSubjectDN().toString() +  
365 				" is not valid. Result=" + result);
366 			return result;
367 		}
368 		
369 		//-- Validate chain validation
370 		ValidateCertificate issuer;
371 		try {
372 			issuer = new ValidateCertificate (this.issuerCertificate, this.caList, this.ocsp, this.crl);
373 		} catch (CertificateCANotFoundException e) {
374 			logger.debug ("[ValidateCertificate.validate] :: Certificate with issuerDN=" + certificate.getIssuerDN().toString() + 
375 				" not belong to the list of trusted CAs.");
376 			trace.add(certificate, "Certificate issuer is not in the chain validation: " + this.issuerCertificate.getSubjectDN().toString());
377 			return ValidationResult.RESULT_CERTIFICATE_NOT_BELONGS_TRUSTED_CAS;
378 		} catch (Exception e) {
379 			logger.debug ("[ValidateCertificate.validate] :: Error creating Certificate with subject DN=" + 
380 				certificate.getSubjectDN().toString() + ".", e);
381 			trace.add(certificate, "Load issuer certificate (" + this.issuerCertificate.getSubjectDN().toString() +") launch an exception: " + e.getMessage());
382 			return ValidationResult.RESULT_CERTIFICATE_CANNOT_BE_VALIDATED ;
383 		}
384 		result = issuer.validate(validationDate, trace);
385 		if (result != ValidationResult.RESULT_VALID) {
386 			logger.debug ("[ValidateCertificate.validate] :: Certificate with subject DN=" + certificate.getSubjectDN().toString() +  
387 				" has a chain validation not valid. Result=" + result);
388 			trace.add(certificate, "Validation response" + result + ": " + CertificateValidator.getString (result));
389 			return ValidationResult.RESULT_CERTIFICATE_CHAIN_VALIDATION_INVALID;
390 		}
391 		
392 		//-- Ok, certificate and chain validation are valid
393 		logger.debug ("[ValidateCertificate.validate] :: Certificate with subject DN=" + certificate.getSubjectDN().toString() +  
394 			" and its chain validation are valid.");
395 		trace.add(certificate, "Validation response" + result + ": " + CertificateValidator.getString (result));
396 		return ValidationResult.RESULT_VALID;
397 	}
398 	
399 	/**
400 	 * Método que obtiene el certificado emisor.
401 	 * 
402 	 * @return Certificado emisor de este certificado.
403 	 */
404 	public ValidateCertificate getIssuerCertificate () {
405 		
406 		logger.debug ("[ValidateCertificate.getIssuerCertificate] :: Start");
407 		
408 		try {
409 			return new ValidateCertificate (this.issuerCertificate, this.caList, this.ocsp, this.crl);
410 		} catch (Exception e) {
411 			// No se va a dar ya que la cadena de confianza se verifica en la inicialización
412 			// del objeto
413 			logger.info("[ValidateCertificate.getIssuerCertificate]::No se ha podido obtener el emisor del certificado", e);
414 			return null;
415 		} 
416 	}
417 	
418 	/**
419 	 * Método que obtiene la cadena de confianza del certificado. El primer
420 	 * elemento del array será el emisor del certificado.
421 	 * 
422 	 * @return Cadena de confianza de este certificado
423 	 */
424 	public List<ValidateCertificate> getCertificationChainAsList () {
425 		
426 		logger.debug ("[ValidateCertificate.getCertificationChainAsList] :: Start");
427 		
428 		List certificateChain = new ArrayList ();
429 		ValidateCertificate certificate = this;
430 		while (true) {
431 			ValidateCertificate issuer = certificate.getIssuerCertificate();
432 			if (issuer.equals(certificate)) {
433 				break;
434 			}
435 			certificateChain.add (issuer);
436 			certificate = issuer;
437 		}
438 		
439 		return certificateChain;
440 	}
441 	
442 	/**
443 	 * Método que obtiene la cadena de confianza del certificado. El primer
444 	 * elemento del array será el propio certificado.
445 	 * 
446 	 * @return Cadena de confianza del certificado (incluyendo el propio certificado)
447 	 */
448 	public List<ValidateCertificate> getCompleteCertificationChainAsList () {
449 		
450 		logger.debug ("[ValidateCertificate.getCompleteCertificationChain] :: Start");
451 		
452 		List certificateChain = new ArrayList ();
453 		ValidateCertificate certificate = this;
454 		certificateChain.add(certificate);
455 		while (true) {
456 			ValidateCertificate issuer = certificate.getIssuerCertificate();
457 			if (issuer.equals(certificate)) {
458 				break;
459 			}
460 			certificateChain.add (issuer);
461 			certificate = issuer;
462 		}
463 		
464 		return certificateChain;
465 	}
466 	
467 	/**
468 	 * Método que obtiene la cadena de confianza del certificado. El primer
469 	 * elemento del array será el emisor del certificado.
470 	 * 
471 	 * @return Cadena de confianza de este certificado
472 	 */
473 	public ValidateCertificate[] getCertificationChain () {
474 		
475 		logger.debug ("[ValidateCertificate.getCertificationChain] :: Start");
476 		
477 		return (ValidateCertificate[])getCertificationChainAsList().toArray(new ValidateCertificate[0]);
478 	}
479 	
480 	/**
481 	 * Método que obtiene la cadena de confianza del certificado. El primer
482 	 * elemento del array será el propio certificado.
483 	 * 
484 	 * @return Cadena de confianza del certificado (incluyendo el propio certificado)
485 	 */
486 	public ValidateCertificate[] getCompleteCertificationChain () {
487 		
488 		logger.debug ("[ValidateCertificate.getCertificationChain] :: Start");
489 		
490 		return (ValidateCertificate[])getCompleteCertificationChainAsList().toArray(new ValidateCertificate[0]);
491 	}
492 	
493 	/**
494 	 * Método que obtiene la cadena de confianza del certificado. El primer
495 	 * elemento del array será el propio certificado.
496 	 * 
497 	 * @return Cadena de confianza del certificado (incluyendo el propio certificado)
498 	 */
499 	public X509Certificate[] getCompleteCertificationChainAsX509Array () {
500 		
501 		logger.debug ("[ValidateCertificate.getCompleteCertificationChainAsX509Array] :: Start");
502 		
503 		List<ValidateCertificate> lChain = getCompleteCertificationChainAsList();
504 		X509Certificate[] arrayCertificates = new X509Certificate[lChain.size()];
505 		int i = 0;
506 		for (Iterator<ValidateCertificate> iterator = lChain.iterator(); iterator.hasNext();) {
507 			ValidateCertificate validateCertificate = iterator.next();
508 			arrayCertificates[i] = validateCertificate.toX509Certificate();
509 			i++;
510 		}
511 		
512 		return arrayCertificates;
513 	}
514 	
515 	/**
516 	 * Método que obtiene la cadena de confianza del certificado. Puede darse el caso de que
517 	 * hayan varios certificados para el mismo emisor (SHA1 y SHA256). En esos casos se
518 	 * obtendrán los dos certificados en el nivel.
519 	 * 
520 	 * @return Cadena de confianza del certificado (incluyendo el propio certificado)
521 	 */
522 	public List<List<ValidateCertificate>> getCertificationChainSeveralIssuers () {
523 		
524 		logger.debug ("[ValidateCertificate.getCertificationChainSeveralIssuers] :: Start");
525 		
526 		List<List<ValidateCertificate>> result = new ArrayList<List<ValidateCertificate>>();
527 		
528 		//-- Añado el primer elemento
529 		List<ValidateCertificate> l = new ArrayList<ValidateCertificate>();
530 		l.add(this);
531 		result.add(l);
532 		
533 		//-- Resto de la cadena
534 		List<List<X509Certificate>> chain = caList.getCertificatesChain(this.certificate);
535 		for(List<X509Certificate> lista : chain) {
536 			l = new ArrayList<ValidateCertificate>();
537 			for(X509Certificate x509Certificate : lista) {
538 				try {
539 					l.add(new ValidateCertificate(x509Certificate, caList));
540 				} catch (Exception e) {
541 					// No se debería dar
542 					logger.info("No se puede pasar a ValidateCertificate \n" + x509Certificate, e);
543 				} 
544 			}
545 			result.add(l);
546 		}
547 		return result;
548 	}
549 	
550 	/**
551 	 * Método que obtiene todos los clientes OCSP que pueden validar este 
552 	 * certificado. <br><br>
553 	 * En un primer paso comprueba si existe en el caList un* fichero de validación, 
554 	 * si es así y en él se encuentran las URLs de los OCSPs para validar este 
555 	 * certificado se devuelven.<br><br>
556 	 * 
557 	 * Si no es así se devuelven los clientes OCSP que apuntan a las URLs indicadas
558 	 * en la extensión Authority Information Access (AIA) del certificado.
559 	 * 
560 	 * @return Clientes OCSP para validar este certificado
561 	 */
562 	public OCSPClient[] getOCSPClients () {
563 		
564 		logger.debug ("[ValidateCertificate.getOCSPClients]::Entrada");
565 		
566 		List lOCSPClients = new ArrayList ();
567 		
568 		//-- Comprobar si hay cliente OCSP por el validationXML
569 		if (this.validationXML != null) {
570 			String issuerCommonName = getCommonNameOrDN (this.issuerCertificate);
571 			
572 			//-- Validate with OCSPs
573 			if (this.validationXML.getOCSPList(issuerCommonName) != null && 
574 					!this.validationXML.getOCSPList(issuerCommonName).isEmpty()) {
575 				
576 				for (Iterator iterator = this.validationXML.getOCSPList(issuerCommonName).iterator(); iterator
577 						.hasNext();) {
578 					
579 					lOCSPClients.add (iterator.next());
580 				
581 				}
582 				
583 				//-- Si se han encontrado se devuelven
584 				if (!lOCSPClients.isEmpty()) {
585 					return (OCSPClient[]) lOCSPClients.toArray(new OCSPClient[0]);
586 				}
587 			}
588 		}
589 		
590 		//-- Obtenerlos de la clase padre
591 		return super.getOCSPClients();
592 
593 	}
594 	
595 	/**
596 	 * Método que obtiene la traza de los pasos dados durante la validación. Lo normal
597 	 * es que se llame a este método tras la validación si se desea obtener una traza
598 	 * de lo sucedido.
599 	 * 
600 	 * @return Traza con los pasos dados durante la validación
601 	 */
602 	public ValidatingTrace getTrace () {
603 		return this.trace;
604 	}
605 
606 	/**
607 	 * Obtiene un objeto CRL de acuerdo al valor de la extensión CRL Distribution Point
608 	 * del certificado. Si hay más de una CRL definida, el método devuelve la primera
609 	 * a la que puede tener acceso.
610 	 * 
611 	 * @return CRL para validar el certificado
612 	 * @throws Exception No se puede obtener la CRL
613 	 */
614 	public CRL getCRL() throws CertificateFieldException, InvalidCRLException {
615 		
616 		logger.debug("[ValidateCertificate.getCRL]:: Init");
617 		
618 		//-- Try to get CRL if the certificate indicates how to obtain it with a URL
619 		String crlURLs [] = null;
620 		try {
621 			crlURLs = getCrlUrls();
622 		} catch (CertificateFieldException e) {
623 			trace.add(certificate, "Cannot read CRL Distribution Point URL from certificate");
624 			throw e;
625 		}
626 		
627 		if (crlURLs == null || crlURLs.length == 0) {
628 			logger.debug ("[ValidateCertificate.getCRL_URLs] :: CRL Distribution Point URL is not found in certificate");
629 			trace.add(certificate, "CRL Distribution Point URL is not found in certificate");
630 			throw new CertificateFieldException ("CRL Distribution Point URL is not found in certificate");
631 		}
632 		
633 		return getCRL (crlURLs);
634 	}
635 		
636 	//-- Private methods
637 	
638 	/*
639 	 * Method that validates the certificate (doen't validate its chain validation). The steps 
640 	 * to validate:
641 	 * <ul>
642 	 * 	<li>Try to get the OCSP from the Authority Information Access (AIA): validate with OCSP</li>
643 	 *  <li>Try to get the CRL from the CRL Distribution Point: validate with CRL</li>
644 	 * </ul>
645 	 * Validation date indicates when the time the validation occurs.
646 	 * 
647 	 * @param validationDate Validation date
648 	 * @return Validation value
649 	 */
650 	private int validateCertificate (Date validationDate) {
651 		
652 		logger.debug ("[ValidateCertificate.validateCertificate] :: Start :: " + validationDate);
653 		
654 		//-- Check if the certificate has expired
655 		if (certificate.getNotBefore().after(validationDate)) {
656 			logger.debug ("[ValidateCertificate.validateCertificate] :: Certificate with subject DN=" + certificate.getSubjectDN().toString() + 
657 				" will not active until " + dateFormat.format(certificate.getNotBefore()) + ".");
658 			trace.add(certificate, "Certificate will not active until " + dateFormat.format(certificate.getNotBefore()));
659 			return ValidationResult.RESULT_CERTIFICATE_NOT_ACTIVE;
660 		}
661 		if (certificate.getNotAfter().before(validationDate)) {
662 			logger.debug ("[ValidateCertificate.validateCertificate] :: Certificate with subject DN=" + certificate.getSubjectDN().toString() + 
663 				" has expired in " + dateFormat.format(certificate.getNotBefore()) + ".");
664 			trace.add(certificate, "Certificate has expired in " + dateFormat.format(certificate.getNotBefore()));
665 			return ValidationResult.RESULT_CERTIFICATE_NOT_ACTIVE;
666 		}
667 		
668 		int result = ValidationResult.RESULT_CERTIFICATE_CANNOT_BE_VALIDATED;
669 
670 		//-- Try to validate with service
671 		
672 		
673 		//-- Try to validate with a ValidationXML
674 		try {
675 			result = validateWithValidationXML (validationDate);
676 		}catch (Exception e) {
677 			trace.add(certificate, "Error validating with a validation XML");
678 			logger.debug ("[ValidateCertificate.validateCertificate] :: Error validating with a validation XML", e);
679 		}
680 		
681 		if (result == ValidationResult.RESULT_CERTIFICATE_CANNOT_BE_VALIDATED) {
682 			//-- Try to validate with the OCSP whose URL can be in the certificate
683 			try {
684 				result = validateWithOCSPInformation (validationDate);
685 			}catch (Exception e) {
686 				trace.add(certificate, "Error validating with OCSP");
687 				logger.debug ("[ValidateCertificate.validateCertificate] :: Error validating with OCSP", e);
688 			}
689 		}
690 		
691 		if (result == ValidationResult.RESULT_CERTIFICATE_CANNOT_BE_VALIDATED) {
692 			//-- Try to validate with the CRL whose URL can be in the certificate
693 			try {
694 				result = validateWithCRLInformation (validationDate);
695 			}catch (Exception e) {
696 				trace.add(certificate, "Error validating with CRL");
697 				logger.debug ("[ValidateCertificate.validateCertificate] :: Error validating with CRL", e);
698 			}
699 		}
700 		
701 		if (result != ValidationResult.RESULT_CERTIFICATE_CANNOT_BE_VALIDATED) {
702 			logger.debug ("[ValidateCertificate.validateCertificate] :: Certificate validated :: result=" + result);
703 			return result;
704 		} 
705 		
706 		logger.debug ("[ValidateCertificate.validateCertificate] :: Cannot validate certificate");
707 		trace.add(certificate, "Certificate cannot be validated");
708 		return ValidationResult.RESULT_CERTIFICATE_CANNOT_BE_VALIDATED ;
709 	}
710 	
711 	/*
712 	 * Validate with information stored in a validation XML
713 	 * Validation date indicates when the time the validation occurs.
714 	 * 
715 	 * @param validationDate Validation date
716 	 * @return Validation result
717 	 */
718 	private int validateWithValidationXML(Date validationDate) {
719 		
720 		logger.debug("[ValidateCertificate.validateWithValidationXML]:: Init :: " + validationDate);
721 
722 		//-- If the validation XML is not found returns
723 		if (this.validationXML != null) {
724 			String issuerCommonName = getCommonNameOrDN (this.issuerCertificate);
725 			
726 			//-- Validate with OCSPs
727 			if (this.validationXML.getOCSPList(issuerCommonName) != null && 
728 					!this.validationXML.getOCSPList(issuerCommonName).isEmpty()) {
729 				
730 				for (Iterator iterator = this.validationXML.getOCSPList(issuerCommonName).iterator(); iterator
731 						.hasNext();) {
732 					
733 					OCSPClient ocsp = (OCSPClient) iterator.next();
734 					logger.debug ("[ValidateCertificate.validateWithValidationXML] :: validating in OCSP " + ocsp.getURL());
735 					try {
736 						int result = ocsp.validate(this, getIssuerCertificate(), validationDate);
737 						trace.add(certificate, "OCSP (" + ocsp.getURL() + ") returns response " + result + ": " + CertificateValidator.getString (result));
738 						this.ocsp = ocsp;
739 						return result;
740 					} catch (Exception e) {
741 						logger.debug ("[ValidateCertificate.validateWithValidationXML] :: Cannot validate certificate in OCSP " + ocsp.getURL(), e);
742 						trace.add(certificate, "OCSP (" + ocsp.getURL() + ") launch an exception: " + e.getMessage());
743 					}
744 				}
745 				
746 			}
747 
748 			//-- Validate with CRLs
749 			if (this.validationXML.getCRLList(issuerCommonName) != null && 
750 					!this.validationXML.getCRLList(issuerCommonName).isEmpty()) {
751 				
752 				try {
753 					CRL crl = getCRL((String[]) this.validationXML.getCRLList(issuerCommonName).toArray(new String [0])); 
754 					
755 					int result = validateInCRL (crl, validationDate);
756 					trace.add(certificate, "CRL returns response " + result + ": " + CertificateValidator.getString (result));
757 					this.crl = crl;
758 					return result;
759 				} catch (Exception e) {
760 					logger.debug ("[ValidateCertificate.validateWithCRLInformation] :: Cannot validate certificate in CRL", e);
761 					trace.add(certificate, "Manage CRL throws an exception: " + e.getMessage());
762 				}
763 				
764 			}
765 
766 		}
767 		
768 		return ValidationResult.RESULT_CERTIFICATE_CANNOT_BE_VALIDATED;
769 	}
770 
771 	/*
772 	 * Validate certificate whith the OCSP's URLs stored in the authority information
773 	 * access (IAI) extension of the X.509 certificate.
774 	 * Validation date indicates when the time the validation occurs.
775 	 * 
776 	 * @param validationDate Validation date
777 	 * @return Validation result
778 	 */
779 	private int validateWithOCSPInformation(Date validationDate) {
780 		
781 		logger.debug("[ValidateCertificate.validateWithOCSPInformation]:: Init :: " + validationDate);
782 		
783 		//-- Try to get the OCSP from the Authority Information Access (AIA)
784 		String urlsOCSP [] = null;
785 		try {
786 			urlsOCSP = getOcspUrls();
787 		} catch (Exception e) {
788 			trace.add(certificate, "Cannot read OCSP URL from certificate");
789 		}
790 		
791 		//-- If OCSP URL is not found it is possible that the OCSP is passed in constructor
792 		if ((urlsOCSP == null || urlsOCSP.length == 0) && this.ocsp != null) {
793 			trace.add(certificate, "Using OCSP from child certificate: " + ocsp.getURL());
794 			try {
795 				int result = this.ocsp.validate(this, getIssuerCertificate(), validationDate);
796 				trace.add(certificate, "OCSP (" + ocsp.getURL() + ") returns response " + result + ": " + CertificateValidator.getString (result));
797 
798 				//-- If result is certificate unknown we try to validate with CRL
799 				if (result != ValidationResult.RESULT_CERTIFICATE_UNKNOWN) {
800 					logger.debug ("[ValidateCertificate.validateWithOCSPInformation] :: Certificate with subject DN=" + certificate.getSubjectDN().toString() + 
801 							" has a result in OCSP " + this.ocsp.getURL() + " = " + result);
802 					return result;
803 				}
804 			} catch (Exception e) {
805 				logger.debug ("[ValidateCertificate.validateWithOCSPInformation] :: Cannot validate certificate in OCSP " + this.ocsp.getURL(), e);
806 				trace.add(certificate, "OCSP (" + ocsp.getURL() + ") launch an exception: " + e.getMessage());
807 			}
808 		} else {
809 			//-- OCSPs URLs are in the AIA from certificate
810 			if (urlsOCSP != null) {
811 				for (int i=0;i<urlsOCSP.length;i++) {
812 					try {
813 						OCSPClient ocsp = new OCSPClient (new URL (urlsOCSP[i]));
814 						int result = ocsp.validate(this, getIssuerCertificate(), validationDate);
815 						trace.add(certificate, "OCSP (" + ocsp.getURL() + ") returns response " + result + ": " + CertificateValidator.getString (result));
816 						this.ocsp = ocsp;
817 						return result;
818 					} catch (Exception e) {
819 						logger.debug ("[ValidateCertificate.validateWithOCSPInformation] :: Cannot validate certificate in OCSP " + urlsOCSP[i], e);
820 						trace.add(certificate, "OCSP (" + urlsOCSP[i] + ") launch an exception: " + e.getMessage());
821 					}
822 				}
823 			}
824 		}
825 		
826 		return ValidationResult.RESULT_CERTIFICATE_CANNOT_BE_VALIDATED;
827 	}
828 
829 	/*
830 	 * Validate certificate whith the CRL's URLs stored in the CRL distribution point
831 	 * extension of the X.509 certificate.
832 	 * Validation date indicates when the time the validation occurs.
833 	 * 
834 	 * @param validationDate Validation date
835 	 * @return Result of validation
836 	 */
837 	private int validateWithCRLInformation(Date validationDate) {
838 		
839 		logger.debug("[ValidateCertificate.validateWithCRLInformation]:: Init :: " + validationDate);
840 		
841 		//-- Try to get the CRL from the CRL Distribution Point
842 		CRL crl = null;
843 		try {
844 			crl = getCRL();
845 		} catch (Exception e) {
846 			logger.debug ("[ValidateCertificate.validateWithCRLInformation] :: cannot obtain a CRL");
847 		}
848 		
849 		//-- If does not get the CRL URL it is possible that the CRL is passed in constructor
850 		if (crl == null && this.crl != null) {
851 			trace.add(certificate, "Using CRL from child certificate");
852 			crl = this.crl;
853 		} 
854 		
855 		//-- validate
856 		if (crl != null) {
857 			try {
858 				int result = validateInCRL (crl, validationDate);
859 				trace.add(certificate, "CRL returns response " + result + ": " + CertificateValidator.getString (result));
860 				this.crl = crl;
861 				return result;
862 			} catch (Exception e) {
863 				logger.debug ("[ValidateCertificate.validateWithCRLInformation] :: Cannot validate certificate in CRL", e);
864 				trace.add(certificate, "Manage CRL throws an exception: " + e.getMessage());
865 			}
866 		}
867 		
868 		return ValidationResult.RESULT_CERTIFICATE_CANNOT_BE_VALIDATED;
869 	}
870 
871 	/*
872 	 * Method that validates the certificate against the crl passed as parameter
873 	 * Validation date indicates when the time the validation occurs.
874 	 * 
875 	 * @param validationDate Validation date
876 	 * @param crl CRL used to validate the certificate
877 	 */
878 	private int validateInCRL (CRL crl, Date validationDate) throws Exception {
879 
880 		logger.debug("[ValidateCertificate.validateInCRL]:: Init :: " + Arrays.asList(new Object [] { crl, validationDate }));
881 		
882 		//-- If we have CRLs check that the certificate is not revoked
883 		if (crl == null) {
884 			logger.debug("[ValidateCertificate.validateInCRL] :: CRL is a null value");
885 			throw new Exception ("CRL is a null value");
886 		}
887 		
888 		//-- Check if certificate is in CRL. If it is in we check that revocation date is before validation date
889 		Date revocationDate = crl.getRevocationDate(this);
890 		if (revocationDate != null && (revocationDate.before(validationDate) || revocationDate.equals(validationDate))) {
891 			return ValidationResult.RESULT_CERTIFICATE_REVOKED;
892 		} else {
893 			return ValidationResult.RESULT_VALID;
894 		}
895 	}
896 	
897 	/*
898 	 * Gets the CRL object from an array of CRL's URL. If there are more than one URL, 
899 	 * it returns the first it can get. 
900 	 * 
901 	 * @return Certificate's CRL 
902 	 * @throws InvalidCRLException If it cannot get the CRL
903 	 */
904 	private CRL getCRL(String[] crlURLs) throws InvalidCRLException {
905 		
906 		logger.debug("[ValidateCertificate.getCRL]:: Init :: " + crlURLs);
907 		
908 		if (crlURLs != null) {
909 			for (int i=0;i<crlURLs.length;i++) {
910 				try {
911 					trace.add(certificate, "Get CRL from " + crlURLs[i]);
912 					logger.debug("[ValidateCertificate.getCRL]:: Get CRL from " + crlURLs[i]);
913 					
914 					return new CRL (new URL (crlURLs[i]), this.caList);
915 
916 				} catch (Exception e) {
917 					logger.debug("[ValidateCertificate.getCRL]:: Error getting CRL from " + crlURLs [i]);
918 					trace.add(certificate, "Get CRL (" + crlURLs[i] + ") launch an exception: ");
919 				} 
920 			}
921 			
922 			//-- Cannot get the CRL
923 			logger.debug ("[ValidateCertificate.getCRL_URLs] :: Cannot get the CRL from any URL in the certificate");
924 			trace.add(certificate, "Cannot get any " + crl);
925 			throw new InvalidCRLException ("Cannot get the CRL from any URL in the certificate");
926 		}
927 		
928 		//-- Cannot get URL for a CRL
929 		logger.debug ("[ValidateCertificate.getCRL_URLs] :: Cannot get the CRL's URL in the certificate");
930 		trace.add(certificate, "Cannot get the CRL's URL in the certificate");
931 		throw new InvalidCRLException ("Cannot get the CRL's URL in the certificate");
932 	}
933 	
934 	/*
935 	 * Método que inicializa el objeto tras ser insertado el certificado en el mismo por
936 	 * la clase padre.
937 	 */
938 	private void initialize (CAList caList, OCSPClient ocsp, CRL crl, ValidatingTrace trace) throws CertificateCANotFoundException, NormalizeCertificateException{
939 
940 		if (caList == null) {
941    			logger.info ("[ValidateCertificate.initialize] :: La lista de CAs es nula");
942    			caList = new CAList ();
943 		}
944 		
945 		//-- Load values into fields
946 		this.caList = caList;
947 		this.validationXML = caList.getValidationXML();
948 		this.ocsp = ocsp;
949 		this.crl = crl;
950 		if (trace != null) {
951 			this.trace = trace;
952 		}
953 		
954 		//-- Check if certificate is self signed
955 		if (!isSelfSigned()) {
956 			//-- Comprueba si se puede obtener la cadena de confianza, empezando por el primer elemento
957 			if (!caList.isOwned(certificate)) {
958 	   			//-- The issuer is unknown
959 	   			logger.info ("[ValidateCertificate.validate] :: Falta alguno de los certificados de la cadena de certificación en la lista de certificados de CA");
960 	   			throw new CertificateCANotFoundException ("Falta alguno de los certificados de la cadena de certificación en la lista de certificados de CA");
961 			}
962 		
963 			//-- Comprobar recursivamente el resto de elementos
964 			try {
965 				new ValidateCertificate (caList.getCACertificate(certificate), caList);
966 			} catch (NormalizeCertificateException e) {
967 	   			logger.info ("[ValidateCertificate.validate] :: Alguno de los certificados de la cadena de certificación no ha podido ser normalizado", e);
968 	   			throw new CertificateCANotFoundException ("Alguno de los certificados de la cadena de certificación no ha podido ser normalizado", e);
969 			}
970 			
971 			//-- Load certificate's issuer
972 			this.issuerCertificate = caList.getCACertificate(certificate);
973 		} else {
974 			
975 			//-- Comprobar que el certificado pertenece a la CAList
976 			if (!caList.contains(this.certificate)) {
977 	   			logger.info ("[ValidateCertificate.validate] :: El certificado es autofirmado y no pertenece a la lista de CAs permitidas");
978 	   			throw new CertificateCANotFoundException ("El certificado es autofirmado y no pertenece a la lista de CAs permitidas");
979 			}
980 			
981 			//-- The issuer of certificate is itself
982 			this.issuerCertificate = this.certificate;
983 		}
984 	}
985 	
986 	/*
987 	 * Gets the common name of the certificate
988 	 * 
989 	 * @param certificate Certificate
990 	 * @return Common name of the certificate
991 	 */
992 	private static String getCommonNameOrDN(X509Certificate certificate) {
993 
994 		String dn = certificate.getSubjectDN().toString();
995 		StringTokenizer st = new StringTokenizer (dn, ",");
996 		while (st.hasMoreTokens()) {
997 			String token = st.nextToken().trim();
998 			if (token.startsWith("CN=")) {
999 				return token.substring(3);
1000 			}
1001 		}
1002 		
1003 		return dn;
1004 	}
1005 
1006 	
1007 
1008 }