/** * 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.xades; import java.util.ArrayList; import java.util.Iterator; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import es.mityc.firmaJava.libreria.ConstantesXADES; import es.mityc.firmaJava.libreria.utilidades.I18n; import es.mityc.firmaJava.libreria.utilidades.NombreNodo; import es.mityc.firmaJava.libreria.utilidades.UtilidadTratarNodo; import es.mityc.firmaJava.libreria.xades.errores.BadFormedSignatureException; import es.mityc.firmaJava.libreria.xades.errores.FirmaXMLError; /** * @author Ministerio de Industria, Turismo y Comercio * @version 0.9 beta */ public class UtilidadXadesX implements ConstantesXADES { private static ArrayList<String> NODOS_DE_X = null; static { NODOS_DE_X = new ArrayList<String>(6); NODOS_DE_X.add(SIGNATURE_VALUE); NODOS_DE_X.add(SIGNATURE_TIME_STAMP); NODOS_DE_X.add(COMPLETE_CERTIFICATE_REFS); NODOS_DE_X.add(COMPLETE_REVOCATION_REFS); NODOS_DE_X.add(ATTRIBUTE_CERTIFICATE_REFS); NODOS_DE_X.add(ATTRIBUTE_REVOCATION_REFS); } /** * Obtiene el listado de nodos necesarios para el cálculo del sello de tiempo para XAdES X del tipo 1 (implícito) * en función del esquema XAdES de firma, a partir del nodo SigAndRefs proporcionado, que actúa como tope * Los nodos necesarios son los siguientes: * - SignatureValue * - SignatureTimestamp * - CompleteCertificateRefs * - CompleteRevocationRefs * Opcionalmente en el esquema 1.2.2 y 1.3.2: * - AttributeCertificateRefs * - AttributeRevocationRefs * * @param esquemaXADES * @param firma * @param nodoSigAndRefs * @return ArrayList<Element> Colección de nodos para el cálculo del sello de tiempo de tipo 1 (implícito) SigAndRefsTimeStamp * @throws BadFormedSignatureException Si no existe, o existe más de un nodo, o no se corresponde con el esquema, según sea el caso * @throws FirmaXMLError Si se produce un error al obtener los nodods */ public static ArrayList<Element> obtenerListadoXADESX1imp(String esquemaXADES, Element firma, Element nodoSigAndRefs) throws BadFormedSignatureException, FirmaXMLError { // Se crea la estructura de retorno de elementos ArrayList<Element> resultado = new ArrayList<Element> (); // Se agrega el nodo SignatureValue Element signatureValueNode = null; NodeList signatureValueNodes = firma.getElementsByTagNameNS(SCHEMA_DSIG, SIGNATURE_VALUE); if(signatureValueNodes.getLength() == 1) signatureValueNode = (Element)signatureValueNodes.item(0); else // El nodo SignatureValue no se encuentra o no es único. Número de nodos encontrados: throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_36) + ESPACIO + SIGNATURE_VALUE + ESPACIO + I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_37) + ESPACIO + signatureValueNodes.getLength()); resultado.add(signatureValueNode); // Se obtienen el nodo UnsignedSignatureProperties (padre) Element UnsignedSignaturePropertiesElement = (Element) nodoSigAndRefs.getParentNode(); if (!(new NombreNodo(esquemaXADES, UNSIGNED_SIGNATURE_PROPERTIES).equals( new NombreNodo(UnsignedSignaturePropertiesElement.getNamespaceURI(), UnsignedSignaturePropertiesElement.getLocalName())))) { // El nodo padre de SigAndRefsTimeStamp no es el nodo UnsignedSignatureProperties esperado según esquema throw new BadFormedSignatureException(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_40) + ConstantesXADES.ESPACIO + ConstantesXADES.SIG_AND_REFS_TIME_STAMP + ConstantesXADES.ESPACIO + I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_42)); } // Se discrimina el tipo de esquema XAdES para incluir los nodos if (SCHEMA_XADES_122.equals(esquemaXADES)) { // Búsqueda para el esquemas 1.2.2 (colección de nodos ordenada) // Se agregan los nodos SignatureTimeStamp NombreNodo tagName = new NombreNodo(esquemaXADES, SIGNATURE_TIME_STAMP); ArrayList<Element> nodosSigTimeStamp = UtilidadTratarNodo.obtenerNodos(UnsignedSignaturePropertiesElement, nodoSigAndRefs, tagName); if(nodosSigTimeStamp.size() < 1) // No se pudo encontrar el nodo SignatureTimeStamp throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_21)); resultado.addAll(nodosSigTimeStamp); // Se agrega el nodo CompleteCertificateRefs tagName = new NombreNodo(esquemaXADES, COMPLETE_CERTIFICATE_REFS); ArrayList<Element> nodosCompleteCertificateRefs = UtilidadTratarNodo.obtenerNodos(UnsignedSignaturePropertiesElement, nodoSigAndRefs, tagName); if(!(nodosCompleteCertificateRefs.size() == 1)) // El nodo CompleteCertificateRefs no existe o no es único. Número de nodos encontrados: throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_36) + ESPACIO + COMPLETE_CERTIFICATE_REFS + ESPACIO + I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_37) + ESPACIO + nodosCompleteCertificateRefs.size()); resultado.addAll(nodosCompleteCertificateRefs); // Se agrega el nodo CompleteRevocationRefs tagName = new NombreNodo(esquemaXADES, COMPLETE_REVOCATION_REFS); ArrayList<Element> nodosCompleteRevocationRefs = UtilidadTratarNodo.obtenerNodos(UnsignedSignaturePropertiesElement, nodoSigAndRefs, tagName); if(!(nodosCompleteRevocationRefs.size() == 1)) // El nodo CompleteRevocationRefs no existe o no es único. Número de nodos encontrados: throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_36) + ESPACIO + COMPLETE_REVOCATION_REFS + ESPACIO + I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_37) + ESPACIO + nodosCompleteRevocationRefs.size()); resultado.addAll(nodosCompleteRevocationRefs); if (SCHEMA_XADES_122.equals(esquemaXADES)) { // Se agrega el nodo AttributeCertificateRefs, si existe tagName = new NombreNodo(esquemaXADES, ATTRIBUTE_CERTIFICATE_REFS); ArrayList<Element> nodosAttributeCertificateRefs = UtilidadTratarNodo.obtenerNodos(UnsignedSignaturePropertiesElement, nodoSigAndRefs, tagName); if((nodosAttributeCertificateRefs.size() > 1)) // El nodo AttributeCertificateRefs no es único. número de nodos encontrados: throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_36) + ESPACIO + ATTRIBUTE_CERTIFICATE_REFS + ESPACIO + I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_38) + ESPACIO + nodosAttributeCertificateRefs.size()); // Si se encontró el nodo, se agrega al array if((nodosAttributeCertificateRefs.size() == 1)) resultado.addAll(nodosAttributeCertificateRefs); // Se agrega el nodo AttributeRevocationRefs tagName = new NombreNodo(esquemaXADES, ATTRIBUTE_REVOCATION_REFS); ArrayList<Element> nodosAttributeRevocationRefs = UtilidadTratarNodo.obtenerNodos(UnsignedSignaturePropertiesElement, nodoSigAndRefs, tagName); if((nodosAttributeRevocationRefs.size() > 1)) // El nodo AttributeCertificateRefs no es único. Número de nodos encontrados: throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_36) + ESPACIO + ATTRIBUTE_REVOCATION_REFS + ESPACIO + I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_38) + ESPACIO + nodosAttributeRevocationRefs.size()); // Si se encontró el nodo, se agrega al array if((nodosAttributeRevocationRefs.size() == 1)) resultado.addAll(nodosAttributeRevocationRefs); } } else { // Búsqueda de nodos para el resto de esquemas (1.3.2 sin orden establecido) ArrayList<NombreNodo> nodosABuscar = new ArrayList<NombreNodo> (); // SignatureTimeStamps nodosABuscar.add(new NombreNodo(esquemaXADES, SIGNATURE_TIME_STAMP)); // CompleteCertificateRefs nodosABuscar.add(new NombreNodo(esquemaXADES, COMPLETE_CERTIFICATE_REFS)); // CompleteRevocationRefs nodosABuscar.add(new NombreNodo(esquemaXADES, COMPLETE_REVOCATION_REFS)); // Los nodos AttributeCertificateRefs y AttributeRevocationRefs son opcionales nodosABuscar.add(new NombreNodo(esquemaXADES, ATTRIBUTE_CERTIFICATE_REFS)); nodosABuscar.add(new NombreNodo(esquemaXADES, ATTRIBUTE_REVOCATION_REFS)); // Se realiza la búsqueda ArrayList<Element> nodos = UtilidadTratarNodo.obtenerNodos(UnsignedSignaturePropertiesElement, nodoSigAndRefs, nodosABuscar); resultado.addAll(nodos); } // Se valida que el resultado obtenido sea correcto int[] listaAparicion = new int[6]; Iterator<Element> it = resultado.iterator(); int indexAnterior = 0; while (it.hasNext()) { Element el = it.next(); int index = NODOS_DE_X.indexOf(el.getLocalName()); // 0: SignatureValue, 1: SignatureTimeStamp, 2: CompleteCertificateRefs, // 3: CompleteRevocationRefs, 4: AttributeCertificateRefs, 5: AttributeRevocationRefs if (SCHEMA_XADES_122.equals(esquemaXADES)) { // Si el valor de index es < indexAnterior => el orden es inválido if (index < indexAnterior) { // La cadena de nodos para el sello de tiempo no es válida throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_39)); } else indexAnterior = index; } listaAparicion[index]++; } if ((listaAparicion[0] != 1) || (listaAparicion[1] < 1) || (listaAparicion[2] != 1) || (listaAparicion[3] != 1) || (listaAparicion[4] > 1) || (listaAparicion[5] > 1)) // La cadena de nodos para el sello de tiempo no es valida throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_39)); // Se devuelve la estructura return resultado; } /** * Obtiene el listado de nodos necesarios para el cálculo del sello de tiempo para XAdES X del tipo 2 (explícito) * en función del esquema XAdES de firma, a partir del nodo RefsOnly proporcionado, que actúa como tope * Los nodos necesarios son los siguientes: * - CompleteCertificateRefs * - CompleteRevocationRefs * Opcionalmente en el esquema 1.2.2 y 1.3.2: * - AttributeCertificateRefs * - AttributeRevocationRefs * * @param esquemaXADES * @param firma * @param nodo RefsOnlyTimeStamp * @return ArrayList<Element> Colección de nodos para el cálculo del sello de tiempo de tipo 2 * @throws BadFormedSignatureException Si no existe, o existe más de un nodo, o no se corresponde con el esquema, según sea el caso * @throws FirmaXMLError Si se produce un error al obtener los nodods */ public static ArrayList<Element> obtenerListadoXADESX2exp(String esquemaXADES, Element firma, Element nodoRefsOnly) throws BadFormedSignatureException, FirmaXMLError { // Se crea la estructura de retorno de elementos ArrayList<Element> resultado = new ArrayList<Element> (); // Se obtienen el nodo UnsignedSignatureProperties (padre) Element UnsignedSignaturePropertiesElement = (Element) nodoRefsOnly.getParentNode(); if (!(new NombreNodo(esquemaXADES, UNSIGNED_SIGNATURE_PROPERTIES).equals( new NombreNodo(UnsignedSignaturePropertiesElement.getNamespaceURI(), UnsignedSignaturePropertiesElement.getLocalName())))) { // El nodo padre de RefsOnlyTimeStamp no es el nodo UnsignedSignatureProperties esperado según esquema throw new BadFormedSignatureException(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_40) + ConstantesXADES.ESPACIO + ConstantesXADES.REFS_ONLY_TIME_STAMP + ConstantesXADES.ESPACIO + I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_42)); } // Se discrimina el tipo de esquema XAdES para incluir los nodos if (SCHEMA_XADES_122.equals(esquemaXADES)) { // Búsqueda para el esquema 1.2.2 (colección de nodos ordenada) // Se agregan los nodos CompleteCertificateRefs NombreNodo tagName = new NombreNodo(esquemaXADES, COMPLETE_CERTIFICATE_REFS); ArrayList<Element> nodosCompleteCertificateRefs = UtilidadTratarNodo.obtenerNodos(UnsignedSignaturePropertiesElement, nodoRefsOnly, tagName); if(!(nodosCompleteCertificateRefs.size() == 1)) // El nodo CompleteCertificateRefs no existe o no es único. Número de nodos encontrados: throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_36) + ESPACIO + COMPLETE_CERTIFICATE_REFS + ESPACIO + I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_37) + ESPACIO + nodosCompleteCertificateRefs.size()); resultado.addAll(nodosCompleteCertificateRefs); // Se agregan los nodos CompleteRevocationRefs tagName = new NombreNodo(esquemaXADES, COMPLETE_REVOCATION_REFS); ArrayList<Element> nodosCompleteRevocationRefs = UtilidadTratarNodo.obtenerNodos(UnsignedSignaturePropertiesElement, nodoRefsOnly, tagName); if(!(nodosCompleteRevocationRefs.size() == 1)) // El nodo CompleteRevocationRefs no existe o no es único. Número de nodos encontrados: throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_36) + ESPACIO + COMPLETE_REVOCATION_REFS + ESPACIO + I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_37) + ESPACIO + nodosCompleteRevocationRefs.size()); resultado.addAll(nodosCompleteRevocationRefs); if (SCHEMA_XADES_122.equals(esquemaXADES)) { // Se agrega el nodo AttributeCertificateRefs, si existe tagName = new NombreNodo(esquemaXADES, ATTRIBUTE_CERTIFICATE_REFS); ArrayList<Element> nodosAttributeCertificateRefs = UtilidadTratarNodo.obtenerNodos(UnsignedSignaturePropertiesElement, nodoRefsOnly, tagName); if((nodosAttributeCertificateRefs.size() > 1)) // El nodo AttributeCertificateRefs no es único. número de nodos encontrados: throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_36) + ESPACIO + ATTRIBUTE_CERTIFICATE_REFS + ESPACIO + I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_38) + ESPACIO + nodosAttributeCertificateRefs.size()); // Si se encontró el nodo, se agrega al array if((nodosAttributeCertificateRefs.size() == 1)) resultado.addAll(nodosAttributeCertificateRefs); // Se agrega el nodo AttributeRevocationRefs tagName = new NombreNodo(esquemaXADES, ATTRIBUTE_REVOCATION_REFS); ArrayList<Element> nodosAttributeRevocationRefs = UtilidadTratarNodo.obtenerNodos(UnsignedSignaturePropertiesElement, nodoRefsOnly, tagName); if((nodosAttributeRevocationRefs.size() > 1)) // El nodo AttributeCertificateRefs no es único. Número de nodos encontrados: throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_36) + ESPACIO + ATTRIBUTE_REVOCATION_REFS + ESPACIO + I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_38) + ESPACIO + nodosAttributeRevocationRefs.size()); // Si se encontró el nodo, se agrega al array if((nodosAttributeRevocationRefs.size() == 1)) resultado.addAll(nodosAttributeRevocationRefs); } } else { // Búsqueda de nodos para el resto de esquemas (1.3.2 sin orden establecido) ArrayList<NombreNodo> nodosABuscar = new ArrayList<NombreNodo> (); // CompleteCertificateRefs nodosABuscar.add(new NombreNodo(esquemaXADES, COMPLETE_CERTIFICATE_REFS)); // CompleteRevocationRefs nodosABuscar.add(new NombreNodo(esquemaXADES, COMPLETE_REVOCATION_REFS)); // Los nodos AttributeCertificateRefs y AttributeRevocationRefs son opcionales nodosABuscar.add(new NombreNodo(esquemaXADES, ATTRIBUTE_CERTIFICATE_REFS)); nodosABuscar.add(new NombreNodo(esquemaXADES, ATTRIBUTE_REVOCATION_REFS)); // Se realiza la búsqueda ArrayList<Element> nodos = UtilidadTratarNodo.obtenerNodos(UnsignedSignaturePropertiesElement, nodoRefsOnly, nodosABuscar); resultado.addAll(nodos); } // Se valida que el resultado obtenido sea correcto int[] listaAparicion = new int[6]; Iterator<Element> it = resultado.iterator(); int indexAnterior = 0; while (it.hasNext()) { Element el = it.next(); int index = NODOS_DE_X.indexOf(el.getLocalName()); // 2: CompleteCertificateRefs, // 3: CompleteRevocationRefs, 4: AttributeCertificateRefs, 5: AttributeRevocationRefs if (SCHEMA_XADES_122.equals(esquemaXADES)) { // Si el valor de index es < indexAnterior => el orden es inválido if (index < indexAnterior) { // La cadena de nodos para el sello de tiempo no es válida throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_39)); } else indexAnterior = index; } listaAparicion[index]++; } // Los primeros nodos SignatureValue y SignatureTimeStamp no deben aparecer if ((listaAparicion[0] != 0) || (listaAparicion[1] != 0) || (listaAparicion[2] != 1) || (listaAparicion[3] != 1) || (listaAparicion[4] > 1) || (listaAparicion[5] > 1)) // La cadena de nodos para el sello de tiempo no es valida throw new BadFormedSignatureException(I18n.getResource(LIBRERIAXADES_FIRMAXML_ERROR_39)); // Se devuelve la estructura return resultado; } }