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.certificate;
22  
23  import java.io.File;
24  import java.io.FileNotFoundException;
25  import java.io.InputStream;
26  import java.security.cert.X509Certificate;
27  import java.text.ParseException;
28  import java.util.ArrayList;
29  import java.util.HashSet;
30  import java.util.List;
31  
32  import org.apache.log4j.Logger;
33  import org.bouncycastle.asn1.ASN1ObjectIdentifier;
34  import org.bouncycastle.asn1.x500.style.BCStyle;
35  import org.bouncycastle.asn1.x509.X509Name;
36  
37  import es.accv.arangi.base.certificate.Certificate;
38  import es.accv.arangi.base.certificate.validation.CAList;
39  import es.accv.arangi.base.exception.certificate.CertificateCANotFoundException;
40  import es.accv.arangi.base.exception.certificate.CertificateFieldException;
41  import es.accv.arangi.base.exception.certificate.NormalizeCertificateException;
42  import es.accv.arangi.base.exception.certificate.ValidationXMLException;
43  import es.accv.arangi.base.util.AlternativeNameElement;
44  import es.accv.arangi.certificate.field.DatosRepresentacionBoletinOficial;
45  import es.accv.arangi.certificate.field.DatosRepresentacionDesconocido;
46  import es.accv.arangi.certificate.field.DatosRepresentacionRegistro;
47  import es.accv.arangi.certificate.field.DatosRepresentacionRegistroNotarial;
48  import es.accv.arangi.exception.ResourceNotLoadedException;
49  import es.accv.arangi.util.ArangiUtil;
50  
51  /**
52   * Clase para el tratamiento de los certificados reconocidos de entidad de la ACCV, según la 
53   * política definida en la URL: 
54   * <a href="http://www.accv.es/pdf-politicas/ACCV-CP-10V1.0-c.pdf" target="politica">
55   * http://www.accv.es/pdf-politicas/ACCV-CP-10V1.0-c.pdf</a>
56   * 
57   * @author <a href="mailto:jgutierrez@accv.es">José M Gutiérrez</a>
58   */
59  public class CertificadoEntidad extends CertificadoACCV{
60  
61  	/*
62  	 * Logger de la clas
63  	 */
64  	static Logger logger = Logger.getLogger(CertificadoEntidad.class);
65  	
66  	/**
67  	 * Alias del keystore donde se guarda el certificado
68  	 */
69  	public static final String ALIAS_PKCS11 = "AMBOS";
70  
71  	/**
72  	 * Base del OID de la política de certificados de ep en dispositivo seguro
73  	 */
74  	public static final String POLICY_IN_PKCS11_DEVICE = "1.3.6.1.4.1.8149.3.10";
75  
76  	/**
77  	 * Base del OID de la política de certificados de ep en dispositivo software
78  	 */
79  	public static final String POLICY_IN_SOFTWARE_DEVICE = "1.3.6.1.4.1.8149.3.22";
80  
81  	/*
82  	 * Lista de SKI de los certificados de CA de explotación
83  	 */
84  	private static HashSet setExplotationCACertificates = new HashSet();
85  	
86  	/*
87  	 * Lista de SKI de los certificados de CA de test
88  	 */
89  	private static HashSet setTestCACertificates = new HashSet();
90  	
91  	/**
92  	 * Constructor con un certificado X509Certificate
93  	 * 
94  	 * @param certificate Certificado en formato X.509
95  	 * @throws CertificateCANotFoundException No se ha encontrado alguno de los certificados de
96  	 * las CA que tratan este certificado en el classpath
97  	 * @throws NormalizeCertificateException El certificado no puede ser normalizado al formato
98  	 * 	reconocido por el proveedor criptográfico de Arangi o su firma no es correcta o no
99  	 * 	puede ser analizada
100 	 */
101 	public CertificadoEntidad(X509Certificate certificate) throws CertificateCANotFoundException, NormalizeCertificateException {
102 		super(certificate, getCAList());
103 	}
104 	
105 	/**
106 	 * Constructor con un fichero que contiene un certificado
107 	 * 
108 	 * @param fileCertificate Fichero que contiene un certificado en formato X.509
109 	 * @throws CertificateCANotFoundException No se ha encontrado alguno de los certificados de
110 	 * las CA que tratan este certificado en el classpath
111 	 * @throws NormalizeCertificateException El certificado no puede ser normalizado al formato
112 	 * 	reconocido por el proveedor criptográfico de Arangi o su firma no es correcta o no
113 	 * 	puede ser analizada
114 	 * @throws FileNotFoundException El fichero no existe
115 	 */
116 	public CertificadoEntidad(File fileCertificate) throws CertificateCANotFoundException, NormalizeCertificateException, FileNotFoundException {
117 		super(fileCertificate, getCAList());
118 	}
119 	
120 	/**
121 	 * Constructor con un fichero que contiene un certificado
122 	 * 
123 	 * @param isCertificate Stream de lectura a un certificado en formato X.509
124 	 * @throws CertificateCANotFoundException No se ha encontrado alguno de los certificados de
125 	 * las CA que tratan este certificado en el classpath
126 	 * @throws NormalizeCertificateException El certificado no puede ser normalizado al formato
127 	 * 	reconocido por el proveedor criptográfico de Arangi o su firma no es correcta o no
128 	 * 	puede ser analizada
129 	 */
130 	public CertificadoEntidad(InputStream isCertificate) throws CertificateCANotFoundException, NormalizeCertificateException {
131 		super(isCertificate, getCAList());
132 	}
133 	
134 	/**
135 	 * Constructor con un fichero que contiene un certificado
136 	 * 
137 	 * @param contenidoCertificado Contenido de un certificado en formato X.509
138 	 * @throws CertificateCANotFoundException No se ha encontrado alguno de los certificados de
139 	 * las CA que tratan este certificado en el classpath
140 	 * @throws NormalizeCertificateException El certificado no puede ser normalizado al formato
141 	 * 	reconocido por el proveedor criptográfico de Arangi o su firma no es correcta o no
142 	 * 	puede ser analizada
143 	 */
144 	public CertificadoEntidad(byte[] contenidoCertificado) throws CertificateCANotFoundException, NormalizeCertificateException {
145 		super(contenidoCertificado, getCAList());
146 	}
147 	
148 	//-- Métodos públicos
149 	
150 	/**
151 	 * Comprueba si el certificado es de una CA de test
152 	 * 
153 	 * @return Cierto si el certificado es de una CA de test
154 	 */
155 	public boolean isTestCertificate () {
156 		logger.debug("[CertificadoCiudadano.isTestCertificate]::Entrada");
157 		return setTestCACertificates.contains(getIssuerKeyIdentifier());
158 	}
159 	
160 	/**
161 	 * Método que devuelve el nombre de la entidad
162 	 * 
163 	 * @return Nombre de la entidad
164 	 */
165 	public String getName () {
166 		return getCommonName();
167 	}
168 	
169 	/**
170 	 * Método que devuelve el nombre del representante de la entidad
171 	 * 
172 	 * @return Nombre del representante de la entidad
173 	 */
174 	public String getAgentName () {
175 		return getElementSubject(X509Name.GIVENNAME);
176 	}
177 	
178 	/**
179 	 * Método que devuelve el primer apellido del representante de la entidad
180 	 * 
181 	 * @return Primer apellido del representante de la entidad
182 	 */
183 	public String getAgentFirstSurname () {
184 		
185 		logger.debug ("[CertificadoEntidad.getAgentFirstSurname]::Entrada");
186 		
187 		return getNombreCompleto()[1].trim();
188 	}
189 	
190 	/**
191 	 * Método que devuelve el segundo apellido del representante de la entidad
192 	 * 
193 	 * @return Segundo apellido del representante de la entidad
194 	 */
195 	public String getAgentSecondSurname () {
196 		
197 		logger.debug ("[CertificadoEntidad.getAgentSecondSurname]::Entrada");
198 		
199 		return getNombreCompleto()[2].trim();
200 	}
201 	
202 	/**
203 	 * Método que devuelve los apellidos del representante de la entidad
204 	 * 
205 	 * @return Apellidos del representante de la entidad
206 	 */
207 	public String getAgentSurnames () {
208 		
209 		logger.debug ("[CertificadoEntidad.getAgentSurnames]::Entrada");
210 		
211 		return getAgentFirstSurname() + " " + getAgentSecondSurname();
212 	}
213 	
214 	/**
215 	 * Método que devuelve el NIF del representante de la entidad
216 	 * 
217 	 * @return NIF del titular del certificado
218 	 */
219 	public String getAgentNIF () {
220 		
221 		logger.debug ("[CertificadoEntidad.getAgentNIF]::Entrada");
222 		
223 		try {
224 			return getSubjectAlternativeNameElement(OID_USERID);
225 		} catch (CertificateFieldException e) {
226 			logger.info ("[CertificadoEntidad.getAgentNIF]::No se puede obtener el NIF del representante", e);
227 			return null;
228 		}
229 	}
230 	
231 	/**
232 	 * Obtiene la información que relaciona al representante con la entidad en
233 	 * los certificados cualificados de entidad como una tira de texto.
234 	 * 
235 	 * @return Tira de texto con la información de representación
236 	 */
237 	public String getRepresentationDataString() {
238 		return getElementSubject(new ASN1ObjectIdentifier("2.5.4.13"));
239 	}
240 	
241 	/**
242 	 * Obtiene la información que relaciona al representante con la entidad en
243 	 * los certificados cualificados de entidad. Estos datos se incluyen en el 
244 	 * certificado y pueden ser una entrada en un registro, un registro notarial, 
245 	 * una entrada en un boletín o cualquier otra cosa.<br>
246 	 * Los certificados generados antes de Julio de 2016 no dispondrán de este
247 	 * campo.
248 	 * 
249 	 * @return En caso de que exista el campo se devolverá un objeto que puede ser
250 	 * 	de las siguientes clases: DatosRepresentacionRegistro, DatosRepresentacionRegistroNotarial,
251 	 * 	DatosRepresentacionBoletinOficial o DatosRepresentacionDesconocido. Si el
252 	 * 	campo no existe se devolverá null.
253 	 */
254 	public Object getRepresentationData() {
255 		String descripcion = getRepresentationDataString();
256 		logger.debug ("[CertificadoEntidad.getRepresentationData]::Descripcion: " + descripcion);
257 		if (descripcion == null) {
258 			return null;
259 		}
260 		
261 		String[] elementos = descripcion.split("/");
262 		if (descripcion.startsWith("R:")) {
263 			DatosRepresentacionRegistro datos = new DatosRepresentacionRegistro();
264 			datos.setRegistro(elementos[0].substring(elementos[0].indexOf(":") + 1));
265 			datos.setHoja(elementos[1]);
266 			datos.setTomo(elementos[2]);
267 			datos.setSeccion(elementos[3]);
268 			datos.setLibro(elementos[4]);
269 			datos.setFolio(elementos[5]);
270 			if (!elementos[6].trim().equals("")) {
271 				try {
272 					datos.setFecha(ArangiUtil.SIMPLE_DATE_FORMAT.parse(elementos[6]));
273 				} catch (ParseException e) {
274 					logger.info("No se puede parsear la fecha '" + elementos[6] + "");
275 				}
276 			}
277 			datos.setInscripcion(elementos[7]);
278 			return datos;
279 		} else if (descripcion.startsWith("N:")) {
280 			DatosRepresentacionRegistroNotarial datos = new DatosRepresentacionRegistroNotarial();
281 			datos.setNotario(elementos[0].substring(elementos[0].indexOf(":") + 1));
282 			datos.setNumeroProtocolo(elementos[1]);
283 			if (!elementos[2].trim().equals("")) {
284 				try {
285 					datos.setFechaOtorgamiento(ArangiUtil.SIMPLE_DATE_FORMAT.parse(elementos[2]));
286 				} catch (ParseException e) {
287 					logger.info("No se puede parsear la fecha '" + elementos[6] + "");
288 				}
289 			}
290 			return datos;
291 		} else if (descripcion.startsWith("B:")) {
292 			DatosRepresentacionBoletinOficial datos = new DatosRepresentacionBoletinOficial();
293 			datos.setBoletin(elementos[0].substring(elementos[0].indexOf(":") + 1));
294 			if (!elementos[1].trim().equals("")) {
295 				try {
296 					datos.setFecha(ArangiUtil.SIMPLE_DATE_FORMAT.parse(elementos[1]));
297 				} catch (ParseException e) {
298 					logger.info("No se puede parsear la fecha '" + elementos[6] + "");
299 				}
300 			}
301 			datos.setNumeroResolucion(elementos[2]);
302 			return datos;
303 		} else {
304 			DatosRepresentacionDesconocido datos = new DatosRepresentacionDesconocido(descripcion);
305 			return datos;
306 		}
307 	}
308 	
309 	/**
310 	 * Método que obtiene el CIF de la entidad.
311 	 * 
312 	 * @return CIF de la entidad
313 	 */
314 	public String getCIF() {
315 		
316 		logger.debug ("[CertificadoEntidad.getCIF]::Entrada");
317 		
318 		return getElementSubject(BCStyle.SERIALNUMBER);
319 	}
320 	
321 	/**
322 	 * Método que obtiene el CIF de la entidad codificado según el ETSI
323 	 * (sólo para certificados cualificados de sello de entidad).
324 	 * 
325 	 * @return CIF de la entidad según el ETSI
326 	 */
327 	public String getCIFETSI() {
328 		
329 		logger.debug ("[CertificadoEntidad.getCIFETSI]::Entrada");
330 		
331 		return getElementSubject(new ASN1ObjectIdentifier("2.5.4.97"));
332 	}
333 	
334 	/**
335 	 * Método que devuelve la dirección de correo electrónico de la entidad
336 	 * 
337 	 * @return E-mail de la entidad titular del certificado
338 	 */
339 	public String getEmail () {
340 		
341 		logger.debug ("[CertificadoEntidad.getEmail]::Entrada");
342 		
343 		List altNames;
344 		try {
345 			altNames = getSubjectAlternativeName();
346 		} catch (CertificateFieldException e) {
347 			logger.info ("[CertificadoEntidad.getEmail]::No ha sido posible obtener el e-mail de la entidad", e);
348 			return null;
349 		}
350 	
351 		//-- Es el primer elemento del nombre alternativo
352 		return (String) ((AlternativeNameElement) altNames.get(0)).getValue();
353 	}
354 	
355 	/**
356 	 * El certificado se encuentra en un dispositivo PKCS#11
357 	 * 
358 	 * @return Cierto si el certificado se encuentra en un dispositivo PKCS#11
359 	 */
360 	public boolean isInPkcs11Device () {
361 		logger.debug ("[CertificadoEmpleadoPublico.isInPkcs11Device]::Entrada");
362 		
363 		for (String policyOID : getPolicyOIDs()) {
364 			if (policyOID.startsWith(POLICY_IN_PKCS11_DEVICE)) {
365 				return true;
366 			}
367 		}
368 		
369 		return false;
370 	}
371 	
372 	/**
373 	 * El certificado se encuentra en un dispositivo software (PKCS#12)
374 	 * 
375 	 * @return Cierto si el certificado se encuentra en un dispositivo software (PKCS#12)
376 	 */
377 	public boolean isInSoftwareDevice () {
378 		logger.debug ("[CertificadoEmpleadoPublico.isInSoftwareDevice]::Entrada");
379 		
380 		for (String policyOID : getPolicyOIDs()) {
381 			if (policyOID.startsWith(POLICY_IN_SOFTWARE_DEVICE)) {
382 				return true;
383 			}
384 		}
385 		
386 		return false;
387 	}
388 	
389 	@Override
390 	public boolean isCipherCertificate() {
391 		return false;
392 	}
393 
394 	@Override
395 	public boolean isSigningCertificate() {
396 		return true;
397 	}
398 	
399 	/**
400 	 * Obtiene la lista de certificados de CA y raíz que conforman las posibles cadenas
401 	 * de confianza de los certificados de esta clase. 
402 	 */
403 	public static CAList getCAList() throws CertificateCANotFoundException {
404 		
405 		//-- Añadir los certificados de test y de explotación
406 		List lCACertificates = getCAListExlotation();
407 		lCACertificates.addAll(getCAListTest());
408 		
409 		CAList caList;
410 		try {
411 			caList = new CAList (lCACertificates);
412 		} catch (NormalizeCertificateException e) {
413 			//-- Si algún certificado no puede ser normalizado lo pasamos como que no
414 			//-- se ha podido cargar
415 			logger.info ("[CertificadoEntidad.getCAList]::Alguno de los certificados de las CA no ha podido ser " +
416 					"normalizado a lo esperado por el proveedor criptográfico de Arangi", e);
417 			throw new CertificateCANotFoundException ("Alguno de los certificados de las CA no ha podido ser " +
418 					"normalizado a lo esperado por el proveedor criptográfico de Arangi", e);
419 		};
420 		
421 		//-- Añadir el fichero para validar los certificados de test
422 		try {
423 			caList.setValidationXML(ArangiUtil.loadFile("file/validation_data_accv_test.xml"));
424 		} catch (ValidationXMLException e) {
425 			//-- Si no se ha podido parsear el fichero de validación lo pasamos como que
426 			//-- no se han podido cargar los certificados de las CA
427 			logger.info ("[CertificadoEntidad.getCAList]::No ha sido posible parsear el fichero de validación XML", e);
428 			throw new CertificateCANotFoundException ("No ha sido posible parsear el fichero de validación XML", e);
429 		} catch (ResourceNotLoadedException e) {
430 			//-- Si no se encuentra pasaremos sin él, sólo que no funcionarán los certificados de test
431 			logger.info ("[CertificadoEntidad.getCAList]::No ha sido posible obtener el fichero de validación XML", e);
432 		}
433 		
434 		return caList;
435 	}
436 
437 	//-- Métodos protected
438 	
439 	/**
440 	 * Usado por la clase CertificateFactory para dar de alta la clase en la lista
441 	 * de tipos de certificados.
442 	 * 
443 	 * @return OID base de la política
444 	 */
445 	protected static String [] getBasePolicies () {
446 		return new String[] { 
447 				POLICY_IN_PKCS11_DEVICE, // certificados en tarjeta
448 				POLICY_IN_SOFTWARE_DEVICE // certificados en software
449 		};
450 	}
451 
452 	//-- Métodos privados
453 	
454 	/*
455 	 * Obtiene la lista de certificados de CA y raíz que conforman las posibles cadenas
456 	 * de confianza de los certificados de explotación de esta clase. 
457 	 */
458 	private static List getCAListExlotation() throws CertificateCANotFoundException {
459 		
460 		//-- Añadir los certificados de explotación
461 		List lCACertificates = new ArrayList ();
462 		X509Certificate certificate = ArangiUtil.loadCertificate("certificate/ACCV-CA1");
463 		setExplotationCACertificates.add(Certificate.getSubjectKeyIdentifier(certificate));
464 		lCACertificates.add(certificate);
465 		
466 		certificate = ArangiUtil.loadCertificate("certificate/ROOT_CA");
467 		setExplotationCACertificates.add(Certificate.getSubjectKeyIdentifier(certificate));
468 		lCACertificates.add(certificate);
469 		
470 		//-- Nueva CA
471 		certificate = ArangiUtil.loadCertificate("certificate/ACCV-CA110-SHA256");
472 		setExplotationCACertificates.add(Certificate.getSubjectKeyIdentifier(certificate));
473 		lCACertificates.add(certificate);
474 		
475 		certificate = ArangiUtil.loadCertificate("certificate/ACCVRAIZ1");
476 		setExplotationCACertificates.add(Certificate.getSubjectKeyIdentifier(certificate));
477 		lCACertificates.add(certificate);
478 		
479 		return lCACertificates;
480 	}
481 	
482 	/*
483 	 * Obtiene la lista de certificados de CA y raíz que conforman las posibles cadenas
484 	 * de confianza de los certificados de test de esta clase. 
485 	 */
486 	private static List getCAListTest() throws CertificateCANotFoundException {
487 		
488 		//-- Añadir los certificados de test y de explotación
489 		List lCACertificates = new ArrayList ();
490 		X509Certificate certificate = ArangiUtil.loadCertificate("certificate/TEST_SUBCA_WINDOWS3");
491 		setTestCACertificates.add(Certificate.getSubjectKeyIdentifier(certificate));
492 		lCACertificates.add(certificate);
493 		
494 		certificate = ArangiUtil.loadCertificate("certificate/TEST_ROOT_EJBCA");
495 		setTestCACertificates.add(Certificate.getSubjectKeyIdentifier(certificate));
496 		lCACertificates.add(certificate);
497 		
498 		certificate = ArangiUtil.loadCertificate("certificate/ACCVCATEST110");
499 		setTestCACertificates.add(Certificate.getSubjectKeyIdentifier(certificate));
500 		lCACertificates.add(certificate);
501 		
502 		certificate = ArangiUtil.loadCertificate("certificate/ROOTEJB4TEST");
503 		setTestCACertificates.add(Certificate.getSubjectKeyIdentifier(certificate));
504 		lCACertificates.add(certificate);
505 		
506 		return lCACertificates;
507 	}
508 
509 	/*
510 	 * Obtiene el nombre completo que hay en la extensión Subject Alternative Name como
511 	 * entrada del LDAP. El array tendrá 3 elementos: nombre, apellido 1 y apellido 2
512 	 */
513 	private String [] getNombreCompleto () {
514 		
515 		String nombreCompleto;
516 		try {
517 			nombreCompleto = getSubjectAlternativeNameElement(OID_ID_AT_COMMONNAME);
518 		} catch (CertificateFieldException e) {
519 			logger.info ("[CertificadoEntidad.getNombreCompleto]::No ha sido posible obtener el nombre completo del ciudadano");
520 			return new String [] {"","",""};
521 		}
522 		if (nombreCompleto == null || nombreCompleto.length() == 0) {
523 			logger.info ("[CertificadoEntidad.getNombreCompleto]::No ha sido posible obtener el nombre completo del ciudadano");
524 			return new String [] {"","",""};
525 		}
526 		return nombreCompleto.split("\\|");
527 
528 	}
529 
530 }