/** * LICENCIA LGPL: * * Esta librería es Software Libre; Usted puede redistribuirlo y/o modificarlo * 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 * <http://www.gnu.org/licenses/>. * * Copyright 2008 Ministerio de Industria, Turismo y Comercio * */ package es.mityc.firmaJava.libreria.utilidades; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate; import java.util.Vector; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.x509.PolicyInformation; import es.mityc.firmaJava.libreria.ConstantesXADES; /** * Funciones de utilidades varias * * @author Ministerio de Industria, Turismo y Comercio * @version 0.9 beta */ public class UtilidadFirmaElectronica implements ConstantesXADES{ static Log log = LogFactory.getLog(UtilidadFirmaElectronica.class); /** * Decodifica una cadena a UTF-8 * @param input Cadena a decodificar * @return cadena en UTF-8 */ public static String decodeUTF( byte[] input ) { int longitud = input.length; char [] output = new char [ longitud ]; int i = 0; int j = 0; while ( i < longitud ) { int b = input[ i++ ] & 0xff; // clasificado según el alto orden de 3 bits switch ( b >>> 5 ) { default : // codificación del 1 byte // 0xxxxxxx // uso justo de orden bajo de 7 bits // 00000000 0xxxxxxx output[ j++ ] = (char) ( b & 0x7f ); break; case 6: // codificación del 2 byte // 110yyyyy 10xxxxxx // uso bajo de orden de 6 bits int y = b & 0x1f; // uso del orden bajo de 6 bits del byte siguiente // debe tener un orden alto de 10 bits, el cual no comprobaremos int x = input[ i++ ] & 0x3f; // 00000yyy yyxxxxxx output[ j++ ] = (char) ( y << 6 | x ); break; case 7: // codificación del 3 byte // 1110zzzz 10yyyyyy 10xxxxxx // assert ( b & 0x10 ) // == 0 : "UTF8Decoder does not handle 32-bit characters"; if ( (b & 0x10) == 0 ){ throw new RuntimeException ( UTF8DECODER_ERROR) ; } // uso del orden bajo de 4 bits int z = b & 0x0f; // uso del orden bajo de 6 bits del siguiente byte // debería tener un orden alto de 10 bits, el cual no comprobaremos y = input[ i++ ] & 0x3f; // uso bajo del orden de 6 bits del siguiente byte // debería tener un orden alto de 10 bits, el cual no comprobaremos x = input[ i++ ] & 0x3f; // zzzzyyyy yyxxxxxx int asint = ( z << 12 | y << 6 | x ); output[ j++ ] = (char) asint; break; } } return new String( output, 0 , j ); } /** * @param listaCertificadosTemp Lista de certificados temporales * @param emisorDN * @return */ public static Vector<X509Certificate> filtraCertificados(Vector<X509Certificate> listaCertificadosTemp, String emisorDN){ String[] allIssuers = emisorDN.split(ALMOHADILLA) ; Vector<X509Certificate> devuelveCertificados = new Vector<X509Certificate>(); int longitudCertificados = listaCertificadosTemp.size(); for (int a=0;a<longitudCertificados ; a++){ X509Certificate certTemp = listaCertificadosTemp.get(a) ; int longitudIssuers = allIssuers.length; for (int b=0;b<longitudIssuers;b++){ if(certTemp.getIssuerDN().toString().indexOf(allIssuers[b]) >= 0 ){ devuelveCertificados.add(certTemp); break ; } } } return devuelveCertificados ; } /** * * @param listaCertificadosTemp Lista de certificados temporales * @return */ public static Vector<X509Certificate> filtraDNIe(Vector<X509Certificate> listaCertificadosTemp){ if (log.isTraceEnabled()) log.trace("Filtrando certificados del DNIe..."); Vector<X509Certificate> returnCertificates = new Vector<X509Certificate>(); ASN1InputStream asn1IS = null; int longitudCertificados = listaCertificadosTemp.size(); for (int a=0; a< longitudCertificados; a++){ X509Certificate certTemp = listaCertificadosTemp.get(a) ; if (UtilidadDNIe.isCertDNIe(certTemp.getIssuerDN().toString())) { try { // El certificado de autenticación tiene una certificate policy 2.16.724.1.2.2.2.4 // El certificado de firma tiene una certificate policy 2.16.724.1.2.2.2.3 // Recupera la certificate policy de este certificado byte[] policies = certTemp.getExtensionValue(CERTIFICATE_POLICIES_OID); if (policies != null) { //Falsos positivos asn1IS = new ASN1InputStream(policies); // Una extensión de certificado va como DER-encoded OCTET (ver getExtensionValue de X509Extension) ASN1OctetString ext = (ASN1OctetString)((ASN1InputStream)asn1IS).readObject(); //asn1IS.close(); asn1IS = new ASN1InputStream(ext.getOctets()); ASN1Sequence seq = (ASN1Sequence)asn1IS.readObject(); // Solo hay una PolicyInformation para el DNIe PolicyInformation pi = new PolicyInformation((ASN1Sequence)seq.getObjectAt(0)); if (UtilidadDNIe.POLICY_OID_CERTIFICADO_AUTENTICACION_DNIE.equals(pi.getPolicyIdentifier().getId())) continue; } returnCertificates.add(certTemp); } catch (Exception ex) { returnCertificates.add(certTemp); } finally{ if (asn1IS != null){ try { asn1IS.close(); } catch (IOException e) { log.error(e); } } } } else returnCertificates.add(certTemp); } return returnCertificates; } public static String obtenerTipoReference(String esquema) { String tipoEsquema = null; if ((SCHEMA_XADES_132).equals(esquema)) tipoEsquema = SCHEMA_XADES + SIGNED_PROPERTIES; else if ((SCHEMA_XADES_122).equals(esquema)) tipoEsquema = SCHEMA_XADES_122 + SIGNED_PROPERTIES; else if ((SCHEMA_XADES_111).equals(esquema)) tipoEsquema = SCHEMA_XADES_111 + SIGNED_PROPERTIES; else { log.error(I18n.getResource(LIBRERIAXADES_VALIDARFIRMA_ERROR1)); return null; } return tipoEsquema; } // TODOLARGO: incluir también los OIDs private static final String DIGEST_ALG_SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1"; private static final String DIGEST_ALG_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#sha256"; private static final String DIGEST_ALG_SHA256_enc = "http://www.w3.org/2001/04/xmlenc#sha256"; private static final String DIGEST_ALG_SHA256_hmac = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256"; private static final String DIGEST_ALG_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#sha512"; private static final String DIGEST_ALG_SHA512_enc = "http://www.w3.org/2001/04/xmlenc#sha512"; private static final String DIGEST_ALG_SHA512_hmac = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512"; private static final String DIGEST_ALG_SHA224 = "http://www.w3.org/2001/04/xmldsig-more#sha224"; private static final String DIGEST_ALG_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#sha384"; private static final String DIGEST_ALG_MD2 = "http://www.w3.org/2001/04/xmldsig-more#md2"; private static final String DIGEST_ALG_MD4 = "http://www.w3.org/2001/04/xmldsig-more#md4"; private static final String DIGEST_ALG_MD5 = "http://www.w3.org/2001/04/xmldsig-more#md5"; private static final String DIGEST_ALG_RIPEMD128 = "http://www.w3.org/2001/04/xmldsig-more#ripemd128"; private static final String DIGEST_ALG_RIPEMD160 = "http://www.w3.org/2001/04/xmldsig-more#ripemd160"; private static final String DIGEST_ALG_RIPEMD256 = "http://www.w3.org/2001/04/xmldsig-more#ripemd256"; private static final String DIGEST_ALG_RIPEMD320 = "http://www.w3.org/2001/04/xmldsig-more#ripemd320"; private static final String DIGEST_ALG_TIGER = "http://www.w3.org/2001/04/xmldsig-more#tiger"; private static final String DIGEST_ALG_WHIRLPOOL = "http://www.w3.org/2001/04/xmldsig-more#whirlpool"; private static final String DIGEST_ALG_GOST3411 = "http://www.w3.org/2001/04/xmldsig-more#gost3411"; /** * Devuelve el MessageDigest asociado a la uri (según la rfc 3275 y la rfc 4051). * * @param uri Uri que define el algoritmo de digest (según las rfc 3275 y 4051). * @return MessageDigest asociado o null si no hay ninguno disponible para el algoritmo indicado. */ public static MessageDigest getMessageDigest(String uri) { MessageDigest md = null; if (uri != null) { try { if (uri.equals(DIGEST_ALG_SHA1)) md = MessageDigest.getInstance("SHA-1"); else if (uri.equals(DIGEST_ALG_SHA256) || uri.equals(DIGEST_ALG_SHA256_enc) || uri.equals(DIGEST_ALG_SHA256_hmac)) md = MessageDigest.getInstance("SHA-256"); else if (uri.equals(DIGEST_ALG_SHA512) || uri.equals(DIGEST_ALG_SHA512_enc) || uri.equals(DIGEST_ALG_SHA512_hmac)) md = MessageDigest.getInstance("SHA-512"); else if (uri.equals(DIGEST_ALG_SHA224)) md = MessageDigest.getInstance("SHA-224"); else if (uri.equals(DIGEST_ALG_SHA384)) md = MessageDigest.getInstance("SHA-384"); else if (uri.equals(DIGEST_ALG_MD2)) md = MessageDigest.getInstance("MD2"); else if (uri.equals(DIGEST_ALG_MD4)) md = MessageDigest.getInstance("MD4"); else if (uri.equals(DIGEST_ALG_MD5)) md = MessageDigest.getInstance("MD5"); else if (uri.equals(DIGEST_ALG_RIPEMD128)) md = MessageDigest.getInstance("RIPEDM128"); else if (uri.equals(DIGEST_ALG_RIPEMD160)) md = MessageDigest.getInstance("RIPEMD160"); else if (uri.equals(DIGEST_ALG_RIPEMD256)) md = MessageDigest.getInstance("RIPEMD256"); else if (uri.equals(DIGEST_ALG_RIPEMD320)) md = MessageDigest.getInstance("RIPEMD320"); else if (uri.equals(DIGEST_ALG_TIGER)) md = MessageDigest.getInstance("Tiger"); else if (uri.equals(DIGEST_ALG_WHIRLPOOL)) md = MessageDigest.getInstance("WHIRLPOOL"); else if (uri.equals(DIGEST_ALG_GOST3411)) md = MessageDigest.getInstance("GOST3411"); } catch (NoSuchAlgorithmException ex) { log.info("Algoritmo de digest no disponible para: " + uri, ex); } } return md; } }