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.device.model;
22  
23  import iaik.pkcs.pkcs11.Module;
24  import iaik.pkcs.pkcs11.Token;
25  import iaik.pkcs.pkcs11.TokenException;
26  
27  import java.io.IOException;
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.Set;
33  
34  import org.apache.log4j.Logger;
35  
36  import es.accv.arangi.base.device.model.Pkcs11Device;
37  import es.accv.arangi.base.device.model.Pkcs11Manufacturer;
38  import es.accv.arangi.base.exception.device.DeviceNotFoundException;
39  import es.accv.arangi.base.exception.device.IAIKDLLNotFoundException;
40  import es.accv.arangi.base.exception.device.IncorrectPINException;
41  import es.accv.arangi.base.exception.device.IncorrectPUKException;
42  import es.accv.arangi.base.exception.device.LockedPINException;
43  import es.accv.arangi.base.exception.device.ModuleNotFoundException;
44  import es.accv.arangi.base.exception.device.NoSuitableDriversException;
45  import es.accv.arangi.base.exception.device.OpeningDeviceException;
46  
47  /**
48   * Clase para tratar las particularidades del fabricante de tarjetas Siemens.
49   * 
50   * @author <a href="mailto:jgutierrez@accv.es">José M Gutiérrez</a>
51   */
52  public class Pkcs11SiemensManufacturer extends Pkcs11Manufacturer {
53  
54  	/**
55  	 * Logger de la clase
56  	 */
57  	Logger logger = Logger.getLogger(Pkcs11SiemensManufacturer.class);
58  	
59  	/**
60  	 * Constante con el nombre del fabricante
61  	 */
62  	public static final String MANUFACTURER_NAME = "siemens";
63  	
64  	/**
65  	 * Constante con el nombre del módulo para tratar tarjetas inicializadas con el API 2.2
66  	 */
67  	public static final String SIEMENS_2_2_MODULE_NAME = "CardOS_PKCS11.dll";
68  	
69  	/**
70  	 * Constante con el nombre del módulo para tratar tarjetas inicializadas con el API 3.2
71  	 */
72  	public static final String SIEMENS_3_2_MODULE_NAME = "siecap11.dll";
73  	
74  	/**
75  	 * Flag que indica que es necesario instalar la versión 2.2 de los drivers
76  	 */
77  	private boolean version22Needed = false;
78  	
79  	/**
80  	 * Flag que indica que es necesario instalar la versión 3.2 de los drivers
81  	 */
82  	private boolean version32Needed = false;
83  	
84  	/**
85  	 * Constructor
86  	 * 
87  	 * @throws IAIKDLLNotFoundException No se encuentra la DLL de IAIK
88  	 * @throws NoSuitableDriversException El manufacturer no dispone de drivers para
89  	 * 	funcionar en el entorno (Java 32 o 64 bits)
90  	 */
91  	public Pkcs11SiemensManufacturer() throws IAIKDLLNotFoundException, NoSuitableDriversException {
92  		super(MANUFACTURER_NAME, SIEMENS_2_2_MODULE_NAME);
93  	}
94  
95  	/**
96  	 * Obtiene un objeto dispositivo usando la implementación del PKCS#11 
97   	 * del constructor. En caso de que hayan varios dispositivos conectados se 
98   	 * elegirá el primero de ellos. Este método se puede usar para el caso 
99   	 * más habitual: que sólo exista un dispositivo PKCS#11 conectado.
100 	 * 
101 	 * @param pin PIN para abrir el dispositivo
102 	 * @param isPUK Flag que indica si el pin hay que tratarlo como el PUK del
103 	 * 	dispositivo
104 	 * @return Dispositivo abierto con PIN o PUK
105 	 * @throws OpeningDeviceException No ha sido posible abrir el dispositivo
106 	 * @throws LockedPINException El PIN del dispositivo está bloqueado
107 	 * @throws IncorrectPUKException El PUK es incorrecto
108 	 * @throws IncorrectPINException  El PIN es incorrecto
109 	 * @throws ModuleNotFoundException No se ha encontrado el módulo PKCS#11
110 	 * 	para tratar el dispositivo
111 	 * @throws DeviceNotFoundException No existen dispositivos para la 
112 	 * 	libería PKCS#11 o no existe un dispositivo para el valor de 'tokenID'.
113 	 */
114 	public Pkcs11Device getInstance (String pin, boolean isPUK) throws DeviceNotFoundException, ModuleNotFoundException, IncorrectPINException, IncorrectPUKException, LockedPINException, OpeningDeviceException {
115 		return getInstance(-1, pin, isPUK);
116 	}
117 	
118 	/**
119 	 * Obtiene un objeto dispositivo usando la implementación del PKCS#11 
120  	 * del constructor. Concretamente obtiene el dispositivo cuyo ID coincide
121  	 * con el parámetro "deviceId".
122 	 * 
123 	 * @param deviceId ID del dispositivo
124 	 * @param pin PIN para abrir el dispositivo
125 	 * @param isPUK Flag que indica si el pin hay que tratarlo como el PUK del
126 	 * 	dispositivo
127 	 * @return Dispositivo abierto con PIN o PUK
128 	 * @throws OpeningDeviceException No ha sido posible abrir el dispositivo
129 	 * @throws LockedPINException El PIN del dispositivo está bloqueado
130 	 * @throws IncorrectPUKException El PUK es incorrecto
131 	 * @throws IncorrectPINException  El PIN es incorrecto
132 	 * @throws ModuleNotFoundException No se ha encontrado el módulo PKCS#11
133 	 * 	para tratar el dispositivo
134 	 * @throws DeviceNotFoundException No existen dispositivos para la 
135 	 * 	libería PKCS#11 o no existe un dispositivo para el valor de 'tokenID'.
136 	 */
137 	public Pkcs11Device getInstance (long deviceId, String pin, boolean isPUK) throws DeviceNotFoundException, ModuleNotFoundException, IncorrectPINException, IncorrectPUKException, LockedPINException, OpeningDeviceException {
138 		logger.debug("[Pkcs11SiemensManufacturer.getInstance]::Entrada::" + Arrays.asList (new Object [] { deviceId, isPUK, iaikDLLFile } ));
139 		
140 		//-- Pruebo con la versión de la 2.2
141 		this.pkcs11Lib = SIEMENS_2_2_MODULE_NAME;
142 		Pkcs11Device device22 = null;
143 		try {
144 			device22 = super.getInstance(deviceId, pin, isPUK); 
145 			if (testWrite (device22)) {
146 				this.pkcs11LibPath = getPkcs11LibPaths().get(SIEMENS_2_2_MODULE_NAME);
147 				return device22;
148 			} else {
149 				logger.debug("[Pkcs11SiemensManufacturer.getInstance]::El módulo " + SIEMENS_2_2_MODULE_NAME + " no es capaz de escribir en el dispositivo");
150 			}
151 		} catch (ModuleNotFoundException e) {
152 			//-- El módulo no está instalado
153 			logger.debug("[Pkcs11SiemensManufacturer.getInstance]::El módulo " + SIEMENS_2_2_MODULE_NAME + " no está instalado");
154 		} catch (DeviceNotFoundException e) {
155 			logger.debug("[Pkcs11SiemensManufacturer.getInstance]::No hay ningún dispositivo para la versión 2.2 del driver de Siemens");
156 		}
157 		
158 		//-- El módulo 2.2 no está instalado, pruebo con la versión de la 3.2
159 		this.pkcs11Lib = SIEMENS_3_2_MODULE_NAME;
160 		Pkcs11Device device32 = null;
161 		try {
162 			device32 = super.getInstance(deviceId, pin, isPUK);
163 			if (testWrite (device32)) {
164 				this.pkcs11LibPath = getPkcs11LibPaths().get(SIEMENS_3_2_MODULE_NAME);
165 				return device32;
166 			} else {
167 				logger.debug("[Pkcs11SiemensManufacturer.getInstance]::El módulo " + SIEMENS_3_2_MODULE_NAME + " no es capaz de escribir en el dispositivo");
168 			}
169 		} catch (ModuleNotFoundException e) {
170 			//-- El módulo no está instalado
171 			logger.debug("[Pkcs11SiemensManufacturer.getInstance]::El módulo " + SIEMENS_3_2_MODULE_NAME + " no está instalado");
172 			throw new ModuleNotFoundException ("No hay instalado ningún módulo PKCS#11 de Siemens", e);
173 		} 
174 		
175 		//-- Ningún módulo es capaz de escribir en la tarjeta
176 		logger.info("[Pkcs11SiemensManufacturer.getInstance]::Ninguno de los módulos es capaz de escribir en el dispositivo");
177 		if (device22 != null) {
178 			logger.info("[Pkcs11SiemensManufacturer.getInstance]::Es necesario instalar la versión 3.2 de los módulos PKCS#11 Siemens");
179 			version32Needed = true;
180 			return device22;
181 		}
182 		if (device32 != null) {
183 			logger.info("[Pkcs11SiemensManufacturer.getInstance]::Es necesario instalar la versión 2.2 de los módulos PKCS#11 Siemens");
184 			version22Needed = true;
185 			return device32;
186 		}
187 		
188 		//-- No se llegará aquí
189 		return null;
190 	}
191 	
192 	/**
193 	 * Obtiene un objeto dispositivo usando la implementación del PKCS#11 
194  	 * del constructor. En caso de que hayan varios dispositivos conectados se 
195  	 * elegirá el primero de ellos. Este método se puede usar para el caso 
196  	 * más habitual: que sólo exista un dispositivo PKCS#11 conectado.<br><br>
197  	 * 
198  	 * El dispositivo obtenido no está abierto con PIN ni PUK, por lo que su
199  	 * utilización se limitará a obtener información de los certificados que
200  	 * almacena e información general, como su número de serie.
201 	 * 
202 	 * @return Dispositivo sin abrir
203 	 * @throws OpeningDeviceException No ha sido posible obtener una sesión en
204 	 * 	el dispositivo
205 	 * @throws ModuleNotFoundException No se ha encontrado el módulo PKCS#11
206 	 * 	para tratar el dispositivo
207 	 * @throws DeviceNotFoundException No existen dispositivos para la 
208 	 * 	librería PKCS#11 o no existe un dispositivo para el valor de 'tokenID'.
209 	 */
210 	public Pkcs11Device getInstance () throws DeviceNotFoundException, ModuleNotFoundException, OpeningDeviceException {
211 		return getInstance(-1);
212 	}
213 	
214 	/**
215 	 * Obtiene un objeto dispositivo usando la implementación del PKCS#11 
216  	 * del constructor. Concretamente obtiene el dispositivo cuyo ID coincide
217  	 * con el parámetro "deviceId".<br><br>
218 	 * 
219  	 * El dispositivo obtenido no está abierto con PIN ni PUK, por lo que su
220  	 * utilización se limitará a obtener información de los certificados que
221  	 * almacena e información general, como su número de serie.
222 	 *
223 	 * @param deviceId ID del dispositivo
224 	 * @throws OpeningDeviceException No ha sido posible obtener una sesión en
225 	 * 	el dispositivo
226 	 * @throws IAIKDLLNotFoundException No se ha encontrado la DLL de IAIK
227 	 * @throws ModuleNotFoundException No se ha encontrado el módulo PKCS#11
228 	 * 	para tratar el dispositivo
229 	 * @throws DeviceNotFoundException No existen dispositivos para la 
230 	 * 	librería PKCS#11 o no existe un dispositivo para el valor de 'tokenID'.
231 	 */
232 	public Pkcs11Device getInstance (long deviceId) throws DeviceNotFoundException, ModuleNotFoundException, OpeningDeviceException {
233 		logger.debug("[Pkcs11SiemensManufacturer.getInstance]::Entrada::" + Arrays.asList (new Object [] { deviceId } ));
234 		
235 		//-- Pruebo con la versión de la 2.2
236 		this.pkcs11Lib = SIEMENS_2_2_MODULE_NAME;
237 		try {
238 			return super.getInstance(deviceId);
239 		} catch (ModuleNotFoundException e) {
240 			//-- El módulo no está instalado
241 			logger.debug("[Pkcs11SiemensManufacturer.getInstance]::El módulo " + SIEMENS_2_2_MODULE_NAME + " no está instalado");
242 		} 
243 		
244 		//-- El módulo 2.2 no está instalado, pruebo con la versión de la 3.2
245 		this.pkcs11Lib = SIEMENS_3_2_MODULE_NAME;
246 		try {
247 			return super.getInstance(deviceId);
248 		} catch (ModuleNotFoundException e) {
249 			//-- El módulo no está instalado
250 			logger.debug("[Pkcs11SiemensManufacturer.getInstance]::El módulo " + SIEMENS_3_2_MODULE_NAME + " no está instalado");
251 			throw new ModuleNotFoundException ("No hay instalado ningún módulo PKCS#11 de Siemens", e);
252 		} 
253 		
254 	}
255 	
256 	/**
257 	 * Comprueba si el módulo del fabricante está disponible en el equipo
258 	 * 
259 	 * @return Cierto si el módulo está presente
260 	 */
261 	public boolean isModulePresent () {
262 		
263 		//-- Pruebo con la versión de la 2.2
264 		this.pkcs11Lib = SIEMENS_2_2_MODULE_NAME;
265 		if (super.isModulePresent()) {
266 			return true;
267 		} else {
268 			//-- Pruebo con la versión de la 3.2
269 			this.pkcs11Lib = SIEMENS_3_2_MODULE_NAME;
270 			return super.isModulePresent();
271 		}
272 	}
273 	
274 	/**
275 	 * Tras la inicialización determina si es necesario tener instalada la
276 	 * versión 2.2 de los drivers para poder escribir en el dispositivo
277 	 * 	
278 	 * @return Cierto si son necesarios los drivers 2.2
279 	 */
280 	public boolean isVersion22Needed() {
281 		return version22Needed;
282 	}
283 
284 	/**
285 	 * Tras la inicialización determina si es necesario tener instalada la
286 	 * versión 3.2 de los drivers para poder escribir en el dispositivo
287 	 * 	
288 	 * @return Cierto si son necesarios los drivers 3.2
289 	 */
290 	public boolean isVersion32Needed() {
291 		return version32Needed;
292 	}
293 
294 	/**
295 	 * Método que obtiene información de los dispositivos conectados para el
296 	 * fabricante
297 	 * 
298 	 * @return Lista de objetos de tipo Pkcs11Device
299 	 * @throws ModuleNotFoundException No se puede cargar el módulo
300 	 * @throws DeviceNotFoundException No se ha obtenido ningún dispositivo para el módulo
301 	 * @throws OpeningDeviceException No se puede obtener una sesión en el dispositivo
302 	 */
303 	public List getConnectedDevices () throws ModuleNotFoundException, DeviceNotFoundException, OpeningDeviceException  {
304 		
305 		logger.debug("[Pkcs11Manufacturer.getConnectedDevices]::Entrada::" + this.pkcs11Lib);
306 		
307 		//-- Buscar elementos para cada libería
308 		List lDevices = new ArrayList();
309 		
310 		//-- Obtener el módulo
311 		Module module22 = null;
312 		try {
313 			//-- Pruebo con la versión de la 2.2
314 			module22 = Module.getInstance(SIEMENS_2_2_MODULE_NAME, this.iaikDLLFile.getAbsolutePath());
315 			this.pkcs11Lib = SIEMENS_2_2_MODULE_NAME;
316 			logger.debug ("[Pkcs11Manufacturer.getConnectedDevices]::Se ha cargado el módulo '" + SIEMENS_2_2_MODULE_NAME + "'");
317 		} catch (IOException e) {
318 			logger.debug ("[Pkcs11Manufacturer.getConnectedDevices]::No ha sido posible cargar el módulo '" + SIEMENS_2_2_MODULE_NAME + "'");
319 		}
320 		
321 		if (module22 != null) {
322 			//-- Obtener los tokens para el módulo
323 			Token[] tokens = null;
324 			try {
325 				tokens = getTokens(module22, getTreatableManufacturerIds());
326 			} catch (DeviceNotFoundException e) {
327 				logger.debug ("[Pkcs11Manufacturer.getConnectedDevices]::No ha sido posible obtener la lista de dispositivos conectados para el módulo '" + this.pkcs11Lib + "'::" + e.getMessage());
328 			}
329 			
330 			if (tokens != null) {
331 				//-- Para cada token: abrir sesión
332 				for (int i = 0; i < tokens.length; i++) {
333 					try {
334 						lDevices.add (new Pkcs11Device (false, this, this.pkcs11Lib, module22, tokens[i], tokens[i].getTokenInfo(), getSession(tokens[i])));
335 					} catch (TokenException e) {
336 						// -- no se puede obtener la información del token
337 						logger.debug("[Pkcs11Manufacturer.getConnectedDevices]::No se puede obtener información del token", e);
338 					}
339 				}
340 			}
341 		}
342 		
343 		Module module32 = null;
344 		try {
345 			//-- Pruebo con la versión de la 2.2
346 			module32 = Module.getInstance(SIEMENS_3_2_MODULE_NAME, this.iaikDLLFile.getAbsolutePath());
347 			this.pkcs11Lib = SIEMENS_3_2_MODULE_NAME;
348 		} catch (IOException e1) {
349 			logger.debug ("[Pkcs11Manufacturer.getConnectedDevices]::No ha sido posible cargar el módulo '" + SIEMENS_3_2_MODULE_NAME + "'");
350 		}
351 		
352 		if (module22 == null && module32 == null) {
353 			throw new ModuleNotFoundException ("Ninguno de los módulos de Siemens ha podido ser cargado.");
354 		}
355 		
356 		if (module32 != null) {
357 			//-- Obtener los tokens para el módulo
358 			Token[] tokens = null;
359 			try {
360 				tokens = getTokens(module32, getTreatableManufacturerIds());
361 			} catch (DeviceNotFoundException e) {
362 				logger.debug ("[Pkcs11Manufacturer.getConnectedDevices]::No ha sido posible obtener la lista de dispositivos conectados para el módulo '" + this.pkcs11Lib + "'::" + e.getMessage());
363 			}
364 			
365 			if (tokens != null) {
366 				//-- Para cada token: abrir sesión si no existia ya el token abierto por la 2.2
367 				for (int i = 0; i < tokens.length; i++) {
368 					
369 					try {
370 						if (!existeTokenEnLista (tokens[i], lDevices)) {
371 							lDevices.add (new Pkcs11Device (false, this, this.pkcs11Lib, module22, tokens[i], tokens[i].getTokenInfo(), getSession(tokens[i])));
372 						}
373 					} catch (TokenException e) {
374 						// -- no se puede obtener la información del token
375 						logger.debug("[Pkcs11Manufacturer.getConnectedDevices]::No se puede obtener información del token", e);
376 					}
377 				}
378 			}
379 		}
380 		
381 		//-- Si no hay dispositivos lanzar excepción
382 		if (lDevices.isEmpty()) {
383 			logger.debug ("[Pkcs11Manufacturer.getConnectedDevices]::No ha sido posible obtener la lista de dispositivos conectados para Siemens");
384 			throw new DeviceNotFoundException("No hay dispositivos conectados para Siemens");
385 		}
386 		
387 		//-- Devolver tabla
388 		return lDevices;
389 			
390 	}
391 
392 	//-- Implementación del métodos abstractos
393 	
394 	@Override
395 	protected String[] getX86LibrariesNames() {
396 		return new String[] {
397 				// 2.2 (necesitan instalación aparte)
398 				// 3.2
399 				"siecadu8.dll",
400 				"siecacrd.dll",
401 				"gmp4_2_1.dll",
402 				"siecaces.dll",
403 				"siecap15.dll",
404 				"siecap11.dll"
405 		};
406 	}
407 
408 	@Override
409 	protected String[] getX64LibrariesNames() {
410 		return new String[] {
411 		};
412 	}
413 
414 	@Override
415 	protected String[] getX86ResourcesNames() {
416 		return new String[] {
417 				
418 		};
419 	}
420 	
421 	@Override
422 	protected String[] getX64ResourcesNames() {
423 		return new String[] {
424 				
425 		};
426 	}
427 	
428 	@Override
429 	protected Set getTreatableManufacturerIds() {
430 		return null;
431 	}
432 
433 	@Override
434 	public int getPinLength() {
435 		return 8;
436 	}
437 
438 	@Override
439 	public int getPukLength() {
440 		return 10;
441 	}
442 
443 	@Override
444 	protected List<String> getPkcs11Libraries() {
445 		List<String> lPkcs11Libraries = new ArrayList<String>();
446 		lPkcs11Libraries.add(SIEMENS_2_2_MODULE_NAME);
447 		lPkcs11Libraries.add(SIEMENS_3_2_MODULE_NAME);
448 		
449 		return lPkcs11Libraries;
450 	}
451 
452 
453 	
454 	//-- Métodos privados
455 	
456 	/**
457 	 * Prueba si se puede escribir en la tarjeta
458 	 * 
459 	 * @param device Dispositivo a probar
460 	 * @return Cierto si se puede escribir
461 	 */
462 	private boolean testWrite(Pkcs11Device device) {
463 		return !device.getTokenInfo().isWriteProtected();
464 	}
465 
466 	/*
467 	 * Comprueba que el token no esté ya en la lista de dispositivos. Para ello
468 	 * verifica que el ID del slot del token no esté ya en uno de los dispositivos
469 	 * de la lista.
470 	 */
471 	private boolean existeTokenEnLista(Token token, List lDevices) {
472 		for (Iterator iterator = lDevices.iterator(); iterator.hasNext();) {
473 			Pkcs11Device device = (Pkcs11Device) iterator.next();
474 			long a = device.getId();
475 			long b = token.getSlot().getSlotID();
476 			if(device.getId() == token.getSlot().getSlotID()) {
477 				return true;
478 			}
479 		}
480 		
481 		return false;
482 	}
483 
484 	@Override
485 	protected boolean runInX64() {
486 		return false;
487 	}
488 
489 	@Override
490 	protected boolean runInX86() {
491 		return true;
492 	}
493 
494 
495 }