/**
* LICENCIA LGPL:
*
* Esta librería es Software Libre; Usted puede redistribuirla y/o modificarla
* bajo los términos de la GNU Lesser General Public License (LGPL) tal y como
* ha sido publicada por la Free Software Foundation; o bien la versión 2.1 de
* la Licencia, o (a su elección) cualquier versión posterior.
*
* Esta librería se distribuye con la esperanza de que sea útil, pero SIN
* NINGUNA GARANTÍA; tampoco las implícitas garantías de MERCANTILIDAD o
* ADECUACIÓN A UN PROPÓSITO PARTICULAR. Consulte la GNU Lesser General Public
* License (LGPL) para más detalles
*
* Usted debe recibir una copia de la GNU Lesser General Public License (LGPL)
* junto con esta librería; si no es así, escriba a la Free Software Foundation
* Inc. 51 Franklin Street, 5º Piso, Boston, MA 02110-1301, USA o consulte
* .
*
* Copyright 2011 Agencia de Tecnología y Certificación Electrónica
*/
package es.accv.arangi.base.device;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collection;
import org.apache.log4j.Logger;
import es.accv.arangi.base.exception.device.OpeningDeviceException;
import es.accv.arangi.base.exception.device.WindowsNotFoundException;
/**
* SOLO FUNCIONA CON VERSIONES DE JAVA A PARTIR DE LA 1.6.
*
* Clase para tratar el almacén de claves personal de Windows, es decir
* el que contiene los certificados que no son de autoridades de certificación.
*
* Ejemplo de uso:
*
*
* IDocument document = new FileDocument(new File ("/documento.txt"));
* PersonalWindowsKeyStoreManager manager = new PersonalWindowsKeyStoreManager ();
* String aliases = manager.getAliasNamesList();
* for (int i=0;i
* System.out.println ("Certificate: " + manager.getCertificate(aliases[i]));
* System.out.println ("Firma: " + manager.signDocument(document, aliases[i])); // Firma con la clave privada del alias
* }
*
*
* @author José M Gutiérrez
*/
public class PersonalWindowsKeyStoreManager extends AbstractBrowserKeyStoreManager {
/*
* Logger de la clase
*/
Logger logger = Logger.getLogger(PersonalWindowsKeyStoreManager.class);
//-- Constructores
/**
* Constructor: inicializa el keystore personal de Windows.
*
* @throws OpeningDeviceException Error abriendo el keystore personal de Windows
* @throws WindowsNotFoundException No existe el almacén de claves de Windows debido
* a que la ejecución se produce en un sistema operativo diferente
*/
public PersonalWindowsKeyStoreManager () throws OpeningDeviceException, WindowsNotFoundException {
if (!System.getProperty("os.name").contains("indows")) {
logger.info("[PersonalWindowsKeyStoreManager]:: El sistema operativo no es Windows sino " + System.getProperty("os.name"));
throw new WindowsNotFoundException("El sistema operativo no es Windows sino " + System.getProperty("os.name"));
}
this.pin = "";
this.ksType = STORE_TYPE_PERSONAL_WINDOWS;
try {
this.ks = KeyStore.getInstance("Windows-MY");
ks.load(null);
} catch (KeyStoreException e) {
logger.info("[PersonalWindowsKeyStoreManager]::No se puede obtener una instancia del keystore personal de Windows", e);
throw new OpeningDeviceException ("No se puede obtener una instancia del keystore personal de Windows", e);
} catch (NoSuchAlgorithmException e) {
logger.info("[PersonalWindowsKeyStoreManager]::No existe el algoritmo que comprueba la integridad del keystore personal de Windows", e);
throw new OpeningDeviceException ("No existe el algoritmo que comprueba la integridad del keystore personal de Windows", e);
} catch (CertificateException e1) {
logger.info("[PersonalWindowsKeyStoreManager]::Alguno de los certificados del dispositivo no puede ser cargado", e1);
throw new OpeningDeviceException ("Alguno de los certificados del dispositivo no puede ser cargado", e1);
} catch (IOException e1) {
logger.info("[PersonalWindowsKeyStoreManager]::Error de entrada/salida cargando el keystore personal de Windows", e1);
throw new OpeningDeviceException ("Error de entrada/salida cargando el keystore personal de Windows", e1);
}
//-- Renombrar los alias (en IExplorer pueden estar repetidos)
try {
cleanCAPIDuplicateAliases(ks);
} catch (Throwable e) {
logger.info("[PersonalWindowsKeyStoreManager]::No se han podido renombrar los alias duplicados en el repositorio de Windows", e);
}
}
//-- Métodos públicos
/**
* Cerrar el keystore y eliminar el provider de SUN de la lista de proveedores
*/
public void close() {
logger.debug ("Cerrando Keystore...");
ks = null;
logger.debug("Cerrado Keystore...OK");
}
@Override
public void initialize() {
try {
this.ks = KeyStore.getInstance("Windows-MY");
ks.load(null);
cleanCAPIDuplicateAliases(ks);
} catch (Throwable e) {
logger.error("[PersonalWindowsKeyStoreManager.initialize]:: Error al reinicializar el KeyStore", e);
}
}
/* (non-Javadoc)
* @see es.accv.arangi.base.device.DeviceManager#isAliasFree(java.lang.String)
*/
public boolean isAliasFree(String alias){
logger.debug ("[PersonalWindowsKeyStoreManager.isAliasFree]::Entrada::" + alias);
boolean isFree = false;
try {
isFree = !ks.containsAlias(alias);
} catch (KeyStoreException e) {
logger.info("[PersonalWindowsKeyStoreManager.isAliasFree]::Error comprobando si existe el alias '" + alias + "'", e);
}
return isFree;
}
//-- Métodos privados
static void cleanCAPIDuplicateAliases(KeyStore keyStore) throws Throwable {
Field field;
KeyStoreSpi keyStoreVeritable;
field = keyStore.getClass().getDeclaredField("keyStoreSpi");
field.setAccessible(true);
keyStoreVeritable = (KeyStoreSpi)field.get(keyStore);
if("sun.security.mscapi.KeyStore$MY".equals(keyStoreVeritable.getClass().getName())) {
Collection entries;
String alias, hashCode;
X509Certificate[] certificates;
field = keyStoreVeritable.getClass().getEnclosingClass().getDeclaredField("entries");
field.setAccessible(true);
entries = (Collection)field.get(keyStoreVeritable);
for(Object entry : entries) {
field = entry.getClass().getDeclaredField("certChain");
field.setAccessible(true);
certificates = (X509Certificate[])field.get(entry);
hashCode = Integer.toString(certificates[0].hashCode());
field = entry.getClass().getDeclaredField("alias");
field.setAccessible(true);
alias = (String)field.get(entry);
if(!alias.equals(hashCode)) {
field.set(entry, alias.concat(" - ").concat(hashCode));
}
}
}
}
}