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.base.signature;
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.ByteArrayOutputStream;
25  import java.io.File;
26  import java.io.FileInputStream;
27  import java.io.FileNotFoundException;
28  import java.io.FileOutputStream;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.io.OutputStream;
32  import java.io.StringWriter;
33  import java.lang.reflect.Constructor;
34  import java.net.MalformedURLException;
35  import java.net.URI;
36  import java.net.URISyntaxException;
37  import java.net.URL;
38  import java.nio.charset.Charset;
39  import java.security.MessageDigest;
40  import java.security.cert.CertificateEncodingException;
41  import java.security.cert.CertificateException;
42  import java.security.cert.X509Certificate;
43  import java.text.ParseException;
44  import java.text.SimpleDateFormat;
45  import java.util.ArrayList;
46  import java.util.Arrays;
47  import java.util.Date;
48  import java.util.GregorianCalendar;
49  import java.util.HashSet;
50  import java.util.Iterator;
51  import java.util.List;
52  import java.util.Locale;
53  import java.util.Set;
54  
55  import javax.xml.parsers.DocumentBuilder;
56  import javax.xml.parsers.DocumentBuilderFactory;
57  import javax.xml.transform.OutputKeys;
58  import javax.xml.transform.Transformer;
59  import javax.xml.transform.TransformerConfigurationException;
60  import javax.xml.transform.TransformerException;
61  import javax.xml.transform.TransformerFactory;
62  import javax.xml.transform.dom.DOMSource;
63  import javax.xml.transform.stream.StreamResult;
64  import javax.xml.xpath.XPath;
65  import javax.xml.xpath.XPathConstants;
66  import javax.xml.xpath.XPathExpression;
67  import javax.xml.xpath.XPathExpressionException;
68  import javax.xml.xpath.XPathFactory;
69  
70  import org.apache.log4j.Logger;
71  import org.apache.xml.security.exceptions.XMLSecurityException;
72  import org.apache.xml.security.signature.Reference;
73  import org.apache.xml.security.signature.SignedInfo;
74  import org.apache.xml.security.signature.XMLSignature;
75  import org.apache.xml.security.transforms.Transforms;
76  import org.bouncycastle.cert.ocsp.OCSPResp;
77  import org.w3c.dom.Attr;
78  import org.w3c.dom.Document;
79  import org.w3c.dom.Element;
80  import org.w3c.dom.NamedNodeMap;
81  import org.w3c.dom.Node;
82  import org.w3c.dom.NodeList;
83  import org.xml.sax.SAXException;
84  
85  import es.accv.arangi.base.algorithm.HashingAlgorithm;
86  import es.accv.arangi.base.certificate.Certificate;
87  import es.accv.arangi.base.certificate.validation.CAList;
88  import es.accv.arangi.base.certificate.validation.CertificateValidationService;
89  import es.accv.arangi.base.certificate.validation.OCSPResponse;
90  import es.accv.arangi.base.device.DeviceManager;
91  import es.accv.arangi.base.document.FileDocument;
92  import es.accv.arangi.base.document.IDocument;
93  import es.accv.arangi.base.document.InputStreamDocument;
94  import es.accv.arangi.base.document.URLDocument;
95  import es.accv.arangi.base.exception.certificate.validation.MalformedOCSPResponseException;
96  import es.accv.arangi.base.exception.device.LoadingObjectException;
97  import es.accv.arangi.base.exception.device.SearchingException;
98  import es.accv.arangi.base.exception.document.HashingException;
99  import es.accv.arangi.base.exception.document.InitDocumentException;
100 import es.accv.arangi.base.exception.signature.AlgorithmNotSuitableException;
101 import es.accv.arangi.base.exception.signature.NoCoincidentDocumentException;
102 import es.accv.arangi.base.exception.signature.NoDocumentToSignException;
103 import es.accv.arangi.base.exception.signature.SignatureException;
104 import es.accv.arangi.base.exception.signature.SignatureNotFoundException;
105 import es.accv.arangi.base.exception.signature.XMLDocumentException;
106 import es.accv.arangi.base.exception.timestamp.MalformedTimeStampException;
107 import es.accv.arangi.base.mityc.ArangiDocumentPrivateData;
108 import es.accv.arangi.base.mityc.CAListCertStatusRecover;
109 import es.accv.arangi.base.mityc.FileResourceData;
110 import es.accv.arangi.base.mityc.ToxicResourceData;
111 import es.accv.arangi.base.mityc.URLResourceData;
112 import es.accv.arangi.base.mityc.UnknownFileResourceData;
113 import es.accv.arangi.base.mityc.ValidationServicesCertStatusRecover;
114 import es.accv.arangi.base.mityc.XAdESUtil;
115 import es.accv.arangi.base.signature.util.ArangiXAdESPolicyIdentifier;
116 import es.accv.arangi.base.signature.util.ArangiXAdESProductionPlace;
117 import es.accv.arangi.base.signature.util.ObjectIdentifier;
118 import es.accv.arangi.base.signature.util.TSAData;
119 import es.accv.arangi.base.signature.util.XAdESAttachedNodeToSign;
120 import es.accv.arangi.base.signature.util.XAdESAttachedNodeToSignEnveloped;
121 import es.accv.arangi.base.signature.util.XAdESAttachedNodeToSignObject;
122 import es.accv.arangi.base.signature.util.XAdESAttachedSignatureOptions;
123 import es.accv.arangi.base.signature.util.XAdESDataObjectFormat;
124 import es.accv.arangi.base.signature.util.XAdESDetachedSignatureOptions;
125 import es.accv.arangi.base.timestamp.TimeStamp;
126 import es.accv.arangi.base.util.Util;
127 import es.accv.arangi.base.util.validation.ValidationResult;
128 import es.mityc.firmaJava.libreria.ConstantesXADES;
129 import es.mityc.firmaJava.libreria.utilidades.Base64Coder;
130 import es.mityc.firmaJava.libreria.utilidades.NombreNodo;
131 import es.mityc.firmaJava.libreria.utilidades.UtilidadFechas;
132 import es.mityc.firmaJava.libreria.utilidades.UtilidadFirmaElectronica;
133 import es.mityc.firmaJava.libreria.utilidades.UtilidadTratarNodo;
134 import es.mityc.firmaJava.libreria.xades.CanonicalizationEnum;
135 import es.mityc.firmaJava.libreria.xades.DataToSign;
136 import es.mityc.firmaJava.libreria.xades.DatosFirma;
137 import es.mityc.firmaJava.libreria.xades.EnumFormatoFirma;
138 import es.mityc.firmaJava.libreria.xades.ExtraValidators;
139 import es.mityc.firmaJava.libreria.xades.FirmaXML;
140 import es.mityc.firmaJava.libreria.xades.RespYCerts;
141 import es.mityc.firmaJava.libreria.xades.ResultadoValidacion;
142 import es.mityc.firmaJava.libreria.xades.UtilidadXadesX;
143 import es.mityc.firmaJava.libreria.xades.ValidarFirmaXML;
144 import es.mityc.firmaJava.libreria.xades.XAdESSchemas;
145 import es.mityc.firmaJava.libreria.xades.elementos.xades.CRLRef;
146 import es.mityc.firmaJava.libreria.xades.elementos.xades.CRLRefs;
147 import es.mityc.firmaJava.libreria.xades.elementos.xades.CRLValues;
148 import es.mityc.firmaJava.libreria.xades.elementos.xades.CertificateValues;
149 import es.mityc.firmaJava.libreria.xades.elementos.xades.EncapsulatedX509Certificate;
150 import es.mityc.firmaJava.libreria.xades.errores.BadFormedSignatureException;
151 import es.mityc.firmaJava.libreria.xades.errores.FirmaXMLError;
152 import es.mityc.firmaJava.libreria.xades.errores.InvalidInfoNodeException;
153 import es.mityc.firmaJava.role.SimpleClaimedRole;
154 import es.mityc.firmaJava.ts.TSCliente;
155 import es.mityc.firmaJava.ts.TSClienteError;
156 import es.mityc.javasign.ConstantsXAdES;
157 import es.mityc.javasign.certificate.ICertStatus;
158 import es.mityc.javasign.certificate.ICertStatusRecoverer;
159 import es.mityc.javasign.certificate.IOCSPCertStatus;
160 import es.mityc.javasign.certificate.IX509CRLCertStatus;
161 import es.mityc.javasign.xml.refs.AllXMLToSign;
162 import es.mityc.javasign.xml.refs.InternObjectToSign;
163 import es.mityc.javasign.xml.refs.ObjectToSign;
164 import es.mityc.javasign.xml.refs.UnknownExternObjectToSign;
165 
166 /**
167  * Clase base de los tipos de firma XAdES.
168  * 
169  * @author <a href="mailto:jgutierrez@accv.es">José M Gutiérrez</a>
170  */
171 public abstract class XAdESSignature extends Signature {
172 
173 	/**
174 	 * Logger de la clase
175 	 */
176 	static Logger logger = Logger.getLogger(XAdESSignature.class);
177 	
178 	/*
179 	 * Documento XML con el formato XAdES
180 	 */
181 	protected Document xadesDocument;
182 	
183 	/*
184 	 * ID del tag que contiene el documento
185 	 */
186 	protected static final String DEFAULT_ID_TAG_DOCUMENT = "ArangiXadesDocument";
187 
188 	/*
189 	 * Nombre del tag raíz por defecto
190 	 */
191 	protected static final String DEFAULT_ROOT_TAG = "arangi-xades";
192 
193 	/*
194 	 * Nombre de la plantilla para generar los ficheros XAdES
195 	 */
196 	protected static final String TEMPLATE_ARANGI_XADES = "es/accv/arangi/base/template/arangi-xades_template.xml";
197 
198 	/**
199 	 * Esquema de XAdES para realizar las firmas
200 	 */
201 	public static final XAdESSchemas DEFAULT_XADES_SCHEMA = XAdESSchemas.XAdES_132;
202 	
203 	/**
204 	 * URI del esquema de XAdES para realizar las firmas
205 	 */
206 	public static final String DEFAULT_XADES_SCHEMA_URI = DEFAULT_XADES_SCHEMA.getSchemaUri();
207 	
208 	/**
209 	 * Encoding de los XML construidos
210 	 */
211 	public static final String DEFAULT_XML_ENCODING = "UTF-8";
212 	
213 	/**
214 	 * Espacio de nombres de XAdES
215 	 */
216 	protected static String 	xadesNS = ConstantsXAdES.DEFAULT_NS_XADES;
217 	
218 	/**
219 	 * Espacio de nombres para XMLDSig
220 	 */
221 	protected static String 	xmldsigNS = ConstantsXAdES.DEFAULT_NS_XMLSIG;
222 
223 	/*
224 	 * Formato de fechas según el tipo dateTime del XML Schema Part 2 (http://www.w3.org/TR/xmlschema-2/#dateTime)
225 	 */
226 	protected static final SimpleDateFormat xsdDateTimeFormat = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss");
227 
228 	//-- Métodos abstractos
229 	
230 	/**
231 	 * Dado un resultado de validación obtenido con <code>validator.validar</code> devuelve
232 	 * un resultado de validación de Arangí. Tratamiento incluyendo validez de certificados.
233 	 */
234 	protected abstract int tratarResultadoValidacion(ResultadoValidacion resultadoValidacion);
235 	
236 	/**
237 	 * Cada clase hija debe determinar cual es su formato de firma: XAdES-BES, XAdES-T...
238 	 * 
239 	 * @return Formato de firma
240 	 */
241 	protected abstract EnumFormatoFirma getXAdESSignatureFormat ();
242 	
243 	//-- Métodos públicos
244 	
245 	/**
246 	 * Obtiene las fechas de las firmas de acuerdo al tag firmado 'SigningTime'. No se incluye
247 	 * la fecha de las contrafirmas. Esta fecha se obtiene del ordenador en el que se realizó la 
248 	 * firma, por lo que no es de confianza.
249 	 * 
250 	 * @return Fechas de las firmas
251 	 */
252 	public Date[] getSigningTimes() {
253 		logger.debug("[XAdESSignature.getSigningTimes]::Entrada");
254 		
255 		//-- Obtener el nodo
256 		XPathFactory factory = XPathFactory.newInstance();
257 		XPath xpath = factory.newXPath();
258 		ArrayList<Date> alDates = new ArrayList<Date>();
259 		try {
260 			XPathExpression expr = xpath.compile("//*[local-name()='Signature']");
261 			NodeList signatureNodes = (NodeList) expr.evaluate (xadesDocument, XPathConstants.NODESET);
262 			for (int i=0;i<signatureNodes.getLength();i++) {
263 				
264 				Node signatureNode = signatureNodes.item(i);
265 				
266 				//-- No tenemos en cuenta las contrafirmas
267 				if (signatureNode.getParentNode() == null || signatureNode.getParentNode().getLocalName() == null ||
268 						!signatureNode.getParentNode().getLocalName().equals("CounterSignature")) {
269 					expr = xpath.compile("*[local-name()='Object']/*[local-name()='QualifyingProperties']/*[local-name()='SignedProperties']/" +
270 							"*[local-name()='SignedSignatureProperties']/*[local-name()='SigningTime']");
271 					Element signingTimeNode = (Element) expr.evaluate (signatureNode, XPathConstants.NODE);
272 					alDates.add(getXsdDateTimeParse(signingTimeNode.getTextContent()));
273 				}
274 			}
275 			
276 			return  alDates.toArray(new Date[0]);
277 			
278 		} catch (Exception e) {
279 			logger.info ("[XAdESSignature.getSigningTimes]::Error inesperado", e);
280 			return null;
281 		}
282 
283 	}
284 	
285 	/**
286 	 * Obtiene la descripción del documento, siempre que al firmar se añadiese
287 	 * este tag dentro del DataObjectFormat. Si no se añadió devolverá null.
288 	 * 
289 	 * @return Descripción del documento firmado o null
290 	 */
291 	public String getDocumentDescription () {
292 		return getDataObjectFormatValue("Description");
293 	}
294 	
295 	/**
296 	 * Obtiene el tipo MIME del documento, siempre que al firmar se añadiese
297 	 * este tag dentro del DataObjectFormat. Si no se añadió devolverá null.
298 	 * 
299 	 * @return Tipo MIME del documento firmado o null
300 	 */
301 	public String getDocumentMIMEType () {
302 		return getDataObjectFormatValue("MimeType");
303 	}
304 	
305 	/**
306 	 * Obtiene la codificación del documento, siempre que al firmar se añadiese
307 	 * este tag dentro del DataObjectFormat. Si no se añadió devolverá null.
308 	 * 
309 	 * @return Tipo MIME del documento firmado o null
310 	 */
311 	public String getDocumentEncoding () {
312 		return getDataObjectFormatValue("Encoding");
313 	}
314 	
315 	/**
316 	 * Obtiene la firma XAdES como un documento DOM.
317 	 * 
318 	 * @return XML DOM
319 	 */
320 	public Document getDOM () {
321 		return xadesDocument;
322 	}
323 	
324 	/**
325 	 * Método que obtiene un objeto de una de las 3 clases de firmas XAdES en base
326 	 * a la firma que se pasa como parámetro. Para obtener de qué tipo de XAdES se
327 	 * trata se recurrirá a las clases del MITyC.
328 	 * 
329 	 * @param signature Firma XAdES
330 	 * @return Objeto de firma XAdES adecuado a la firma pasada como parámetro
331 	 * @throws FileNotFoundException El fichero no existe
332 	 * @throws XMLDocumentException El fichero no es un XML
333 	 * @throws SignatureException El XML no es un XAdES
334 	 */
335 	public static XAdESSignature getXAdESObject (File signature) throws SignatureException, XMLDocumentException, FileNotFoundException {
336 		return XAdESSignature.getXAdESObject (getDocument(signature));
337 	}
338 	
339 	/**
340 	 * Método que obtiene un objeto de una de las 3 clases de firmas XAdES en base
341 	 * a la firma que se pasa como parámetro. Para obtener de qué tipo de XAdES se
342 	 * trata se recurrirá a las clases del MITyC.
343 	 * 
344 	 * @param isSignature Firma XAdES
345 	 * @return Objeto de firma XAdES adecuado a la firma pasada como parámetro
346 	 * @throws XMLDocumentException El fichero no es un XML
347 	 * @throws SignatureException El XML no es un XAdES
348 	 */
349 	public static XAdESSignature getXAdESObject (InputStream isSignature) throws SignatureException, XMLDocumentException{
350 		return XAdESSignature.getXAdESObject (getDocument(isSignature));
351 	}
352 	
353 	/**
354 	 * Método que obtiene un objeto de una de las 3 clases de firmas XAdES en base
355 	 * a la firma que se pasa como parámetro. Para obtener de qué tipo de XAdES se
356 	 * trata se recurrirá a las clases del MITyC.
357 	 * 
358 	 * @param signature Firma XAdES
359 	 * @return Objeto de firma XAdES adecuado a la firma pasada como parámetro
360 	 * @throws XMLDocumentException 
361 	 * @throws SignatureException 
362 	 */
363 	public static XAdESSignature getXAdESObject (byte[] signature) throws SignatureException, XMLDocumentException {
364 		return XAdESSignature.getXAdESObject (getDocument(signature));
365 	}
366 	
367 	/**
368 	 * Método que obtiene un objeto de una de las 3 clases de firmas XAdES en base
369 	 * a la firma que se pasa como parámetro. Para obtener de qué tipo de XAdES se
370 	 * trata se recurrirá a las clases del MITyC.
371 	 * 
372 	 * @param signature Firma XAdES
373 	 * @return Objeto de firma XAdES adecuado a la firma pasada como parámetro
374 	 * @throws SignatureException El XML no es un XAdES
375 	 * @throws SignatureException No se puede obtener el tipo de XAdES, posiblemente
376 	 * 	porque no se trata de una firma XAdES
377 	 */
378 	public static XAdESSignature getXAdESObject (Document signature) throws SignatureException {
379 		logger.debug("[XAdESSignature.getXAdESObject]::Entrada::" + signature);
380 		
381 		//-- Buscar el elementos que caracterizan al tipo XAdES-X-L
382 		XPathFactory factory = XPathFactory.newInstance();
383 		XPath xpath = factory.newXPath();
384 		NodeList certificateNodes;
385 		try {
386 			XPathExpression expr = xpath.compile("//*[local-name()='RevocationValues']");
387 			certificateNodes = (NodeList) expr.evaluate (signature, XPathConstants.NODESET);
388 			if (certificateNodes != null && certificateNodes.getLength() > 0) {
389 				logger.debug("[XAdESSignature.getXAdESObject]::La firma es un XAdES-X-L");
390 				return new XAdESXLSignature (signature);
391 			}
392 		} catch (Exception e) {
393 			logger.info ("[XAdESSignature.getXAdESObject]::Error buscando el nodo RevocationValues", e);
394 		}
395 
396 		//-- Buscar el elementos que caracterizan al tipo XAdES-T
397 		try {
398 			XPathExpression expr = xpath.compile("//*[local-name()='SignatureTimeStamp']");
399 			certificateNodes = (NodeList) expr.evaluate (signature, XPathConstants.NODESET);
400 			if (certificateNodes != null && certificateNodes.getLength() > 0) {
401 				logger.debug("[XAdESSignature.getXAdESObject]::La firma es un XAdES-T");
402 				return new XAdESTSignature (signature);
403 			}
404 		} catch (Exception e) {
405 			logger.info ("[XAdESSignature.getXAdESObject]::Error buscando el nodo SignatureTimeStamp", e);
406 		}
407 
408 		//-- Buscar el elementos que caracterizan al tipo XAdES-BES
409 		try {
410 			XPathExpression expr = xpath.compile("//*[local-name()='QualifyingProperties']");
411 			certificateNodes = (NodeList) expr.evaluate (signature, XPathConstants.NODESET);
412 			if (certificateNodes != null && certificateNodes.getLength() > 0) {
413 				logger.debug("[XAdESSignature.getXAdESObject]::La firma es un XAdES-BES");
414 				return new XAdESBESSignature(signature);
415 			}
416 		} catch (Exception e) {
417 			logger.info ("[XAdESSignature.getXAdESObject]::Error buscando el nodo QualifyingProperties", e);
418 		}
419 
420 		//-- No es un XAdES
421 		logger.info("[XAdESSignature.getXAdESObject]::El XML no es un XAdES");
422 	    throw new SignatureException("El XML no es un XAdES");
423 		
424 	}
425 	
426 	/**
427 	 * Método para poder validar con el método Signature.validateSignature.<br><br>
428 	 * 
429 	 * Analiza el parámetro y, si se trata de un objeto XAdES, devuelve un 
430 	 * objeto del tipo adecuado.
431 	 * 
432 	 * @param bSignature Firma como array de bytes
433 	 * @return XAdES
434 	 * @throws Exception El parámetro no es un XAdES
435 	 */
436 	public static ISignature getSignatureInstance (byte[] bSignature) throws Exception {
437 		return getXAdESObject(bSignature);
438 	}
439 	
440 	//-- Métodos de Signature
441 	
442 	/**
443 	 * Devuelve los certificados con los que se han realizado las firmas
444 	 * 
445 	 * @return Certificados con los que se ha realizado las firmas
446 	 */
447 	public Certificate[] getCertificates() {
448 
449 		logger.debug ("[XAdESSignature.getCertificates]::Entrada");
450 		
451 		//-- Localizar los certificados de la firma
452 		XPathFactory factory = XPathFactory.newInstance();
453 		XPath xpath = factory.newXPath();
454 		NodeList certificateNodes;
455 		try {
456 			XPathExpression expr = xpath.compile("//*[local-name()='Signature']/*[local-name()='KeyInfo']/*[local-name()='X509Data']/*[local-name()='X509Certificate']");
457 			certificateNodes = (NodeList) expr.evaluate (this.xadesDocument, XPathConstants.NODESET);
458 		} catch (Exception e) {
459 			logger.info ("[XAdESSignature.getCertificates]::Error inesperado", e);
460 			return null;
461 		}
462 
463 		if (certificateNodes == null || certificateNodes.getLength() == 0) {
464 			logger.info("[XAdESSignature.getCertificates]::Falta el elemento 'X509Certificate' de la firma");
465 			return null;
466 		}
467 		
468 		//-- Obtener los certificados
469 		Certificate[] certificates = new Certificate [certificateNodes.getLength()];
470 		for (int i = 0; i < certificateNodes.getLength(); i++) {
471 			try {
472 				X509Certificate x509Cert = Util.getCertificate(Util.decodeBase64(certificateNodes.item(i).getTextContent()));
473 				certificates[i] = new Certificate (x509Cert);
474 			} catch (Exception e) {
475 				logger.info ("[XAdESSignature.getCertificates]::Error inesperado", e);
476 				return null;
477 			}
478 		}
479 
480 		return certificates;
481 	}
482 
483 	/**
484 	 * Devuelve el documento contenido en la firma attached. La cadena devuelta por 
485 	 * este método será la representación en base64 del documento original.
486 	 * 
487 	 * @return Documento contenido en la firma attached o null si la firma es detached
488 	 * @throws SignatureException Error obteniendo el documento de la firma
489 	 * @throws SignatureNotFoundException No se encuentra ninguna firma dentro del 
490 	 * 	fichero XML
491 	 */
492 	public String getAttachedDocument() throws SignatureException, SignatureNotFoundException {
493 
494 		logger.debug ("[XAdESSignature.getAttachedDocument]::Entrada");
495 		
496 		//-- Obtenemos el nodo donde se encuentra la firma. Cogemos la primera, en principio daría igual la elegida 
497 		// si todas son multifirmas
498 		String uriXmlNS = "http://www.w3.org/2000/09/xmldsig#";
499 		NodeList signatureList = xadesDocument.getElementsByTagNameNS(uriXmlNS, "Signature");
500 		Node nodeSignature = null;
501 		if (signatureList.getLength() < 1) {
502 			logger.info("[XAdESSignature.getAttachedDocument]:: No existe ninguna firma en el XAdES");
503 			throw new SignatureNotFoundException("No existe ninguna firma en el XAdES");
504 		} else {
505 			nodeSignature = signatureList.item(0);
506 		}
507 		
508 		logger.debug("[XAdESSignature.getAttachedDocument]:: Obtenido el nodo de firma");
509 		
510 		//-- Obtenemos la referencia al documento. Será la que no empieze por SignedProperties y tenga ID
511 		try {
512 			XMLSignature firmaDocumento = new XMLSignature((Element)nodeSignature, "./");
513 			SignedInfo signedInfo = firmaDocumento.getSignedInfo();
514 			for(int i = 0; i < signedInfo.getLength(); i++){
515 				Reference ref = signedInfo.item(i);
516 	            if (ref.getId() != null && !ref.getId().startsWith("SignedProperties") && !ref.getId().equals("")) {
517 	            	String uri = ref.getURI();
518 	            	if (!uri.startsWith("#")) {
519 						// Sera una firma Dettached
520 						logger.debug("[XAdESSignature.getAttachedDocument]:: Se trata de una firma detached, el método devolverá un valor nulo");
521 						return null;
522 					} else {
523 						// Sera una firma Attached
524 	            		logger.debug("[XAdESSignature.getAttachedDocument]:: Se trata de una firma attached");
525 	            		uri = uri.substring(1);
526 	            		XPathFactory factory = XPathFactory.newInstance();
527 	            		XPath xpath = factory.newXPath();
528 	            		Node node = null;
529 	            		try {
530 	            			XPathExpression expr = xpath.compile("//*[@id='" + uri + "'] | //*[@Id='" + uri + "'] | //*[@iD='" + uri + "'] | //*[@ID='" + uri + "']");
531 	            			node = (Node) expr.evaluate (this.xadesDocument, XPathConstants.NODE);
532 	            		} catch (Exception e) {
533 	            			logger.info ("[XAdESSignature.getAttachedDocument]::Error inesperado", e);
534 	            			return null;
535 	            		}
536 	            		if (node == null) {
537 	            			logger.info ("[XAdESSignature.getAttachedDocument]::No se ha encontrado el elemento con ID=" + uri);
538 	            			return null;
539 	            		}
540 	            		
541 	            		logger.debug("[XAdESSignature.getAttachedDocument]:: Encontrado documento en uri con ID=" + uri);
542 	            		return node.getTextContent();
543 					}
544 				}    
545 			}
546 			
547 		} catch (XMLSecurityException e) {
548 			logger.info("[XAdESSignature.coSign]::Error buscando elementos en el fichero XAdES", e);
549 			throw new SignatureException("Error buscando elementos en el fichero XAdES", e);
550 		}
551 		
552 		//-- No se ha encontrado ninguna referencia
553 		logger.debug("[XAdESSignature.getAttachedDocument]:: No se ha encontrado ninguna referencia con ID=Reference-ID...");
554 		return null;
555 
556 	}
557 
558 	/* (non-Javadoc)
559 	 * @see es.accv.arangi.base.signature.ISignature#isValid(CAList)
560 	 */
561 	public ValidationResult[] isValid(CAList caList) throws SignatureException {
562 
563 		return isValid(null, caList);
564 		
565 	}
566 
567 	/* (non-Javadoc)
568 	 * @see es.accv.arangi.base.signature.ISignature#isValid(IDocument,CAList)
569 	 */
570 	public ValidationResult[] isValid(IDocument document, CAList caList)
571 			throws SignatureException {
572 		
573 		logger.debug("[XAdESSignature.isValid]::Entrada::" + Arrays.asList(new Object[] { document, caList }));
574 	
575 		return isValidCommon(document, caList, null);
576 	}
577 
578 	/* (non-Javadoc)
579 	 * @see es.accv.arangi.base.signature.ISignature#isValid(java.util.List(es.accv.arangi.base.certificate.validation.service.CertificateValidationService))
580 	 */
581 	public ValidationResult[] isValid(List<CertificateValidationService> validationServices)
582 			throws SignatureException {
583 		
584 		return isValid(null, validationServices);
585 		
586 	}
587 
588 	/* (non-Javadoc)
589 	 * @see es.accv.arangi.base.signature.ISignature#isValid(IDocument,java.util.List(es.accv.arangi.base.certificate.validation.service.CertificateValidationService))
590 	 */
591 	public ValidationResult[] isValid(IDocument document, List<CertificateValidationService> validationServices)
592 			throws SignatureException {
593 		
594 		logger.debug("[XAdESSignature.isValid]::Entrada::" + Arrays.asList(new Object[] { document, validationServices }));
595 		
596 		return isValidCommon(document, null, validationServices);
597 	}
598 
599 
600 	/* (non-Javadoc)
601 	 * @see es.accv.arangi.base.signature.ISignature#isValidSignatureOnly()
602 	 */
603 	public ValidationResult[] isValidSignatureOnly() throws SignatureException {
604 		try {
605 			return isValidSignatureOnly(null);
606 		} catch (HashingException e) {
607 			// no se va a dar
608 			logger.info("[XAdESSignature.isValidSignatureOnly]::Error inesperado", e);
609 			throw new SignatureException ("Error inesperado", e);
610 		}
611 	}
612 
613 	/* (non-Javadoc)
614 	 * @see es.accv.arangi.base.signature.ISignature#isValidSignatureOnly(es.accv.arangi.base.document.IDocument)
615 	 */
616 	public ValidationResult[] isValidSignatureOnly(IDocument document) throws HashingException, SignatureException {
617 		
618 		logger.debug("[XAdESSignature.isValidSignatureOnly]::Entrada");
619 		
620 	    ValidarFirmaXML validator = loadValidator (document);
621 	    List<ResultadoValidacion> results;
622 		try {
623 			results = validator.validar(this.xadesDocument, "./", null);
624 		} catch (FirmaXMLError e) {
625 			logger.info("[XAdESSignature.isValidSignatureOnly]::No ha sido posible validar la firma", e);
626 		    throw new SignatureException("No ha sido posible validar la firma", e);
627 		}
628 		
629 		ArrayList<ValidationResult> result = new ArrayList<ValidationResult>();
630 	    for (Iterator<ResultadoValidacion> iterator = results.iterator(); iterator.hasNext();) {
631 			ResultadoValidacion resultadoValidacion = iterator.next();
632 			ValidationResult validationResult = getValidationResultSignatureOnly(resultadoValidacion, false);
633 			if (validationResult != null) {
634 				result.add(validationResult);
635 			}
636 		}
637 		
638 		return result.toArray(new ValidationResult[0]);
639 		
640 	}
641 	
642 	/**
643 	 * Obtiene la codificación del XML que contiene el XAdES
644 	 * 
645 	 * @return Codificación del XML que contiene el XAdES
646 	 */
647 	public String getEncoding() {
648 		if(xadesDocument.getInputEncoding() != null) {
649 			logger.debug("[XAdESSignature.getEncoding]:: Devolviendo " + xadesDocument.getInputEncoding());
650 			return xadesDocument.getInputEncoding();
651 		}
652 		if(xadesDocument.getXmlEncoding() != null) {
653 			logger.debug("[XAdESSignature.getEncoding]:: Devolviendo " + xadesDocument.getXmlEncoding());
654 			return xadesDocument.getXmlEncoding();
655 		}
656 		logger.debug("[XAdESSignature.getEncoding]:: Devolviendo por defecto " + DEFAULT_XML_ENCODING);
657 		return DEFAULT_XML_ENCODING;
658 	}
659 	
660 	/**
661 	 * Obtiene como una cadena de texto el campo SignaturePolicyIdentifier.
662 	 * 
663 	 * @return campo SignaturePolicyIdentifier o null si la firma no es EPES
664 	 */
665 	public String getSignaturePolicyIdentifier () {
666 		logger.debug("[XAdESSignature.getSignaturePolicyIdentifier]::Entrada");
667 		
668 		//-- Obtener el nodo
669 		XPathFactory factory = XPathFactory.newInstance();
670 		XPath xpath = factory.newXPath();
671 		try {
672 			XPathExpression expr = xpath.compile("//*[local-name()='Object']/*[local-name()='QualifyingProperties']/*[local-name()='SignedProperties']/" +
673 					"*[local-name()='SignedSignatureProperties']/*[local-name()='SignaturePolicyIdentifier']");
674 			Node spiNode = (Node) expr.evaluate (xadesDocument, XPathConstants.NODE);
675 			if (spiNode == null) {
676 				logger.debug("[XAdESSignature.getSignaturePolicyIdentifier]::La firma no es EPES");
677 				return null;
678 			}
679 			
680 			return nodeToString(spiNode);
681 			
682 		} catch (Exception e) {
683 			logger.info ("[XAdESSignature.getSignaturePolicyIdentifier]::Error inesperado", e);
684 			return null;
685 		}
686 
687 	}
688 	
689 	/**
690 	 * Obtiene como una cadena de texto el campo SignaturePolicyIdentifier.
691 	 * 
692 	 * @return campo getSignatureProductionPlace o null si la firma no es EPES
693 	 */
694 	public ArangiXAdESProductionPlace getSignatureProductionPlace () {
695 		logger.debug("[XAdESSignature.getSignatureProductionPlace]::Entrada");
696 		
697 		//-- Obtener el nodo
698 		XPathFactory factory = XPathFactory.newInstance();
699 		XPath xpath = factory.newXPath();
700 		try {
701 			XPathExpression expr = xpath.compile("//*[local-name()='Object']/*[local-name()='QualifyingProperties']/*[local-name()='SignedProperties']/" +
702 					"*[local-name()='SignedSignatureProperties']/*[local-name()='SignatureProductionPlace']");
703 			Node sppNode = (Node) expr.evaluate (xadesDocument, XPathConstants.NODE);
704 			if (sppNode == null) {
705 				logger.debug("[XAdESSignature.getSignatureProductionPlace]::La firma no no contiene el elemento SignatureProductionPlace");
706 				return null;
707 			}
708 			
709 			String city = ((Node) xpath.compile("//*[local-name()='City']").evaluate (sppNode, XPathConstants.NODE)).getTextContent();
710 			String state = ((Node) xpath.compile("//*[local-name()='StateOrProvince']").evaluate (sppNode, XPathConstants.NODE)).getTextContent();
711 			String postalCode = ((Node) xpath.compile("//*[local-name()='PostalCode']").evaluate (sppNode, XPathConstants.NODE)).getTextContent();
712 			String country = ((Node) xpath.compile("//*[local-name()='CountryName']").evaluate (sppNode, XPathConstants.NODE)).getTextContent();
713 			
714 			return new ArangiXAdESProductionPlace(city, state, postalCode, country);
715 			
716 		} catch (Exception e) {
717 			logger.info ("[XAdESSignature.getSignatureProductionPlace]::Error inesperado", e);
718 			return null;
719 		}
720 
721 	}
722 	
723 	/**
724 	 * Guarda la firma XAdES en un fichero
725 	 * 
726 	 * @param file Fichero donde se guardará la firma
727 	 * @throws FileNotFoundException No se puede escribir en el fichero
728 	 * @throws XMLDocumentException Errores en la transformación de DOM a un stream 
729 	 * 	de escritura
730 	 */
731 	public void save (File file) throws IOException {
732 		
733 		logger.debug("[XAdESSignature.save]::Entrada::" + file);
734 		
735 		FileOutputStream fos = null;
736 		try {
737 			fos = new FileOutputStream (file);
738 	        save(fos);
739 		} finally {
740 			if (fos != null) {
741 				try {
742 					fos.close();
743 				} catch (IOException e) {
744 					logger.info("[XAdESSignature.save]::No se puede cerrar el stream de escritura al fichero", e);
745 				}
746 			}
747 		}
748 	}
749 	
750 	/**
751 	 * Guarda la firma en un stream de escritura.
752 	 * 
753 	 * @param out Stream de escritura
754 	 * @throws IOException Errores de entrada / salida o durante la transformación DOM a XML
755 	 */
756 	public void save (OutputStream out) throws IOException {
757 		logger.debug("[XAdESSignature.save]::Entrada::" + out);
758 		
759 		try {
760 	        TransformerFactory tf = TransformerFactory.newInstance();
761 	    	Transformer trans = tf.newTransformer();
762 	    	String encoding = xadesDocument.getXmlEncoding();
763 	    	if (encoding == null) {
764 	    		encoding = Charset.defaultCharset().displayName(Locale.getDefault());
765 	    	}
766 	    	trans.setOutputProperty(OutputKeys.ENCODING, encoding);
767 	    	trans.transform(new DOMSource(xadesDocument), new StreamResult(out));
768 		} catch (TransformerConfigurationException e) {
769 			logger.info("[XAdESSignature.save]::No está disponible una implementación para transformar el árbol DOM", e);
770 			throw new IOException ("No está disponible una implementación para transformar el árbol DOM" + e.getMessage());
771 		} catch (TransformerException e) {
772 			logger.info("[XAdESSignature.save]::No está disponible una implementación para transformar el árbol DOM", e);
773 			throw new IOException ("No está disponible una implementación para transformar el árbol DOM" + e.getMessage());
774 		} 
775 	}
776 	
777 	/**
778 	 * Devuelve la firma XAdES como un array de bytes
779 	 * 
780 	 * @return Firma como array de bytes
781 	 */
782 	public byte[] toByteArray () {
783 		logger.debug("[XAdESSignature.toByteArray]::Entrada");
784 		ByteArrayOutputStream baos = new ByteArrayOutputStream();
785 		try {
786 			save(baos);
787 		} catch (IOException e) {
788 			// Raro raro
789 			logger.info("[XAdESSignature.toByteArray]::No ha sido posible guardar en memoria", e);
790 			return null;
791 		}
792 		return baos.toByteArray();
793 
794 	}
795 	
796 	//-- Métodos protected
797 	
798 	/**
799 	 * Construye el objeto en base a un XML que tiene el formato
800 	 * XAdES-BES
801 	 * 
802 	 * @param xmlDocument Documento XML
803 	 */
804 	protected void initialize(Document xmlDocument) {
805 		//TODO Validar que el XML es un XAdES
806 		xadesDocument = xmlDocument;
807 	}
808 	
809 	/**
810 	 * Construye el objeto en base a un fichero XAdES-BES
811 	 * 
812 	 * @param xmlFile Fichero XAdES
813 	 * @throws FileNotFoundException El fichero no existe
814 	 * @throws XMLDocumentException El fichero no parece un XML válido
815 	 */
816 	protected void initialize(File xmlFile) throws FileNotFoundException, XMLDocumentException {
817 		xadesDocument = getDocument(xmlFile);
818 	}
819 
820 	/**
821 	 * Construye el objeto en base a un array de bytes.
822 	 * 
823 	 * @param signature Firma XAdES
824 	 * @throws XMLDocumentException El fichero no parece un XML válido
825 	 */
826 	protected void initialize(byte[] signature) throws XMLDocumentException {
827 		xadesDocument = getDocument(signature);
828 	}
829 
830 	/**
831 	 * Construye el objeto en base a un stream de lectura.
832 	 * 
833 	 * @param isSignature Stream a la firma XAdES
834 	 * @throws XMLDocumentException El fichero no parece un XML válido
835 	 */
836 	protected void initialize(InputStream isSignature) throws XMLDocumentException {
837 		xadesDocument = getDocument(isSignature);
838 	}
839 
840 	/**
841 	 * Obtiene un document de XML en base a un fichero XAdES-BES
842 	 * 
843 	 * @param xmlFile Fichero XAdES-BES
844 	 * @throws FileNotFoundException El fichero no existe
845 	 * @throws XMLDocumentException El fichero no parece un XML válido
846 	 */
847 	private static Document getDocument (File xmlFile) throws FileNotFoundException, XMLDocumentException {
848 		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
849 		dbf.setNamespaceAware(true);
850 		try {
851 			return dbf.newDocumentBuilder().parse(new FileInputStream(xmlFile));
852 		} catch (Exception e) {
853 			logger.info("[XAdESSignature(file)]::El fichero no parece ser un XML válido", e);
854 			throw new XMLDocumentException("El fichero no parece ser un XML válido", e);
855 		} 
856 	}
857 
858 	/**
859 	 * Obtiene un document de XML en base a un array de bytes.
860 	 * 
861 	 * @param signature Firma XAdES-BES
862 	 * @throws XMLDocumentException El fichero no parece un XML válido
863 	 */
864 	private static Document getDocument(byte[] signature) throws XMLDocumentException {
865 		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
866 		dbf.setNamespaceAware(true);
867 		try {
868 			return dbf.newDocumentBuilder().parse(new ByteArrayInputStream(signature));
869 		} catch (Exception e) {
870 			logger.info("[XAdESSignature(byte[])]::La firma no parece ser un XML válido", e);
871 			throw new XMLDocumentException("La firma no parece ser un XML válido", e);
872 		} 
873 	}
874 
875 	/**
876 	 * Obtiene un document de XML en base a un stream de lectura.
877 	 * 
878 	 * @param isSignature Stream a la firma XAdES-BES
879 	 * @throws XMLDocumentException El fichero no parece un XML válido
880 	 */
881 	private static Document getDocument(InputStream isSignature) throws XMLDocumentException {
882 		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
883 		dbf.setNamespaceAware(true);
884 		try {
885 			return dbf.newDocumentBuilder().parse(isSignature);
886 		} catch (Exception e) {
887 			logger.info("[XAdESSignature(byte[])]::La firma no parece ser un XML válido", e);
888 			throw new XMLDocumentException("La firma no parece ser un XML válido", e);
889 		} 
890 	}
891 
892 	/*
893 	 * Obtiene la fecha del sello de tiempos de la firma (Punto 7.3 del estándar).
894 	 * 
895 	 * @return Fecha del sello de tiempos
896 	 * @throws MalformedTimeStampException El sello de tiempos guardado en el fichero XAdES-T no 
897 	 * está bien formado
898 	 */
899 	protected Date getXAdESTimeStampTime () throws MalformedTimeStampException {
900 		logger.debug("[XAdESSignature.getXAdESTimeStampTime]::Entrada");
901 		
902 		//-- Obtener el nodo
903 		XPathFactory factory = XPathFactory.newInstance();
904 		XPath xpath = factory.newXPath();
905 		Element tsNode = null;
906 		try {
907 			XPathExpression expr = xpath.compile("//*[local-name()='UnsignedSignatureProperties']/*[local-name()='SignatureTimeStamp']/*[local-name()='EncapsulatedTimeStamp']");
908 			tsNode = (Element) expr.evaluate (xadesDocument, XPathConstants.NODE);
909 		} catch (Exception e) {
910 			logger.info ("[XAdESSignature.getXAdESTimeStampTime]::Error inesperado", e);
911 			return null;
912 		}
913 		
914 		//-- Obtener el sello de tiempos
915 		TimeStamp timeStamp = new TimeStamp(new ByteArrayInputStream (Util.decodeBase64(tsNode.getTextContent())));
916 		
917 		//-- Obtener fecha
918 		return timeStamp.getTime();
919 
920 	}
921 	
922 	/*
923 	 * Obtiene el certificado de firma del sello de tiempos de la firma (Punto 7.3 del estándar).
924 	 * 
925 	 * @return Certificado de firma del sello de tiempos
926 	 * @throws MalformedTimeStampException El sello de tiempos guardado en el fichero XAdES-T no 
927 	 * está bien formado
928 	 */
929 	protected static Certificate getXAdESTimeStampCertificate (Document xadesDocument) throws MalformedTimeStampException {
930 		logger.debug("[XAdESSignature.getXAdESTimeStampCertificate]::Entrada");
931 		
932 		//-- Obtener el nodo
933 		XPathFactory factory = XPathFactory.newInstance();
934 		XPath xpath = factory.newXPath();
935 		Element tsNode = null;
936 		try {
937 			XPathExpression expr = xpath.compile("//*[local-name()='UnsignedSignatureProperties']/*[local-name()='SignatureTimeStamp']/*[local-name()='EncapsulatedTimeStamp']");
938 			tsNode = (Element) expr.evaluate (xadesDocument, XPathConstants.NODE);
939 		} catch (Exception e) {
940 			logger.info ("[XAdESSignature.getXAdESTimeStampTime]::Error inesperado", e);
941 			return null;
942 		}
943 		
944 		//-- Obtener el sello de tiempos
945 		TimeStamp timeStamp = new TimeStamp(new ByteArrayInputStream (Util.decodeBase64(tsNode.getTextContent())));
946 		
947 		//-- Obtener fecha
948 		return timeStamp.getSignatureCertificate();
949 
950 	}
951 	
952 	/**
953 	 * Método que define la información a firmar para una firma attached
954 	 * 
955 	 * @param docToSign Documento que se firmará
956 	 * @param nodeToSign Nodo del XML que se debe firmar
957 	 * @param signatureParent Nombre del tag que será el padre de los nodos de firma. Si tiene valor nulo
958 	 * 	la firma colgará del nodo raíz.
959 	 * @param certStatusRecover Objeto para determinar estado de certificados. Se utiliza
960 	 * 	a partir del XAdES-C
961 	 * @param tipoXAdES Tipo de XAdES tal y como se establece en las constantes de la clase
962 	 * 	<code>EnumFormatoFirma</code>
963 	 * @parma dof Información para construir el tag DataObjectFormat (puede ser null)
964 	 * @param claimedRoles Roles de la firma
965 	 * @param policyIdentifier Identificador de la política (firmas EPES)
966 	 * @param productionPlace SignatureProductionPlace
967 	 * @param tsaHashingAlgorithm Algoritmo de hashing para el sello de tiempos
968 	 * @return Información de la firma
969 	 */
970 	protected static DataToSign createDataToSignAtached(Document docToSign, XAdESAttachedNodeToSign nodeToSign, 
971 			String signatureParent, URI encoding, ICertStatusRecoverer certStatusRecover, EnumFormatoFirma tipoXAdES, 
972 			XAdESDataObjectFormat dof, String[] claimedRoles, ArangiXAdESPolicyIdentifier policyIdentifier,
973 			ArangiXAdESProductionPlace productionPlace, String tsaHashingAlgorithm) {
974         DataToSign dataToSign = new DataToSign();
975         dataToSign.setXadesFormat(tipoXAdES);
976         if (certStatusRecover != null) {
977         	dataToSign.setCertStatusManager (certStatusRecover);
978         }
979         dataToSign.setEsquema(DEFAULT_XADES_SCHEMA);
980         dataToSign.setXMLEncoding(DEFAULT_XML_ENCODING);
981         dataToSign.setEnveloped(true);
982         dataToSign.setDocument(docToSign);
983         
984         if (policyIdentifier != null) {
985         	dataToSign.setPolicy(policyIdentifier.getSignaturePolicyIdentifier());
986         }
987         if (productionPlace != null) {
988         	dataToSign.setProductionPlace(productionPlace.getCity(), productionPlace.getState(), 
989         			productionPlace.getPostalCode(), productionPlace.getCountry());
990         }
991         
992         String dofDescripcion = null;
993         ObjectIdentifier dofObjectIdentifier = null;
994         String dofMimeType = null;
995         URI dofEncoding = null;
996         if (dof != null) {
997         	dofDescripcion = dof.getDescription();
998         	dofObjectIdentifier = dof.getObjectIdentifier();
999         	dofMimeType = dof.getMimeType();
1000         	dofEncoding = dof.getEncoding();
1001         }
1002         if (nodeToSign instanceof XAdESAttachedNodeToSignEnveloped) {
1003         	dataToSign.addObject(new ObjectToSign(new AllXMLToSign(), dofDescripcion, dofObjectIdentifier, dofMimeType, dofEncoding));
1004         } else {
1005         	dataToSign.addObject(new ObjectToSign(new InternObjectToSign(((XAdESAttachedNodeToSignObject)nodeToSign).getIdToSign()), dofDescripcion, dofObjectIdentifier, dofMimeType, dofEncoding));
1006         }
1007         if (claimedRoles != null) {
1008         	for(String claimedRole : claimedRoles) {
1009         		dataToSign.addClaimedRol(new SimpleClaimedRole(claimedRole));
1010         	}
1011         }
1012         
1013         dataToSign.setParentSignNode(signatureParent);
1014         logger.debug("ParentSignNode: " + docToSign.getDocumentElement().getNodeName());
1015 
1016         if (tsaHashingAlgorithm != null) {
1017 			try {
1018 				String tsaHashingAlgorithmXades = XAdESUtil.getXAdESHashingAlgorithm(tsaHashingAlgorithm);
1019 	       		dataToSign.setAlgDigestTSA(tsaHashingAlgorithmXades);
1020 			} catch (AlgorithmNotSuitableException e) {
1021 				logger.info("No existe el algoritmo de hashing para la TSA");
1022 			}
1023         }
1024 
1025         return dataToSign;
1026 	}
1027 
1028 	/**
1029 	 * Método que define la información a firmar para una firma dettached.
1030 	 * 
1031 	 * @param document Documento que se firmará
1032 	 * @param reference Referencia a la que apuntará la firma
1033 	 * @param certStatusRecover Objeto para determinar estado de certificados. Se utiliza
1034 	 * 	a partir del XAdES-C
1035 	 * @param tipoXAdES Tipo de XAdES tal y como se establece en las constantes de la clase
1036 	 * 	<code>EnumFormatoFirma</code>
1037 	 * @param dof Información para construir el tag DataObjectFormat (puede ser null)
1038 	 * @param claimedRoles Roles de la firma
1039 	 * @param policyIdentifier Identificador de la política (firmas EPES)
1040 	 * @param productionPlace SignatureProductionPlace
1041 	 * @param tsaHashingAlgorithm Algoritmo de hashing para el sello de tiempos
1042 	 * @return Información de la firma
1043 	 * @throws XMLDocumentException
1044 	 */
1045 	protected static DataToSign createDataToSignDetached(IDocument document, String reference, 
1046 			ICertStatusRecoverer certStatusRecover, EnumFormatoFirma tipoXAdES, XAdESDataObjectFormat dof,
1047 			String[] claimedRoles, ArangiXAdESPolicyIdentifier policyIdentifier,
1048 			ArangiXAdESProductionPlace productionPlace, String tsaHashingAlgorithm) {
1049 	    DataToSign dataToSign = new DataToSign();
1050 	    dataToSign.setXadesFormat(tipoXAdES);
1051         if (certStatusRecover != null) {
1052         	dataToSign.setCertStatusManager (certStatusRecover);
1053         }
1054 	    dataToSign.setEsquema(DEFAULT_XADES_SCHEMA);
1055 	    dataToSign.setXMLEncoding(DEFAULT_XML_ENCODING);
1056 	    dataToSign.setEnveloped(false);
1057         if (policyIdentifier != null) {
1058         	dataToSign.setPolicy(policyIdentifier.getSignaturePolicyIdentifier());
1059         }
1060         if (productionPlace != null) {
1061         	dataToSign.setProductionPlace(productionPlace.getCity(), productionPlace.getState(), 
1062         			productionPlace.getPostalCode(), productionPlace.getCountry());
1063         }
1064         
1065         String dofDescripcion = null;
1066         ObjectIdentifier dofObjectIdentifier = null;
1067         String dofMimeType = null;
1068         URI dofEncoding = null;
1069         if (dof != null) {
1070         	dofDescripcion = dof.getDescription();
1071         	dofObjectIdentifier = dof.getObjectIdentifier();
1072         	dofMimeType = dof.getMimeType();
1073         	dofEncoding = dof.getEncoding();
1074         }
1075         
1076         if (tsaHashingAlgorithm != null) {
1077 			try {
1078 				String tsaHashingAlgorithmXades = XAdESUtil.getXAdESHashingAlgorithm(tsaHashingAlgorithm);
1079 	       		dataToSign.setAlgDigestTSA(tsaHashingAlgorithmXades);
1080 			} catch (AlgorithmNotSuitableException e) {
1081 				logger.info("No existe el algoritmo de hashing para la TSA");
1082 			}
1083         }
1084 
1085        	dataToSign.addObject(new ObjectToSign(new UnknownExternObjectToSign(reference, new ArangiDocumentPrivateData(document)),  dofDescripcion, dofObjectIdentifier, dofMimeType, dofEncoding));
1086  
1087        	if (claimedRoles != null) {
1088         	for(String claimedRole : claimedRoles) {
1089         		dataToSign.addClaimedRol(new SimpleClaimedRole(claimedRole));
1090         	}
1091         }
1092 	    return dataToSign;
1093 	}
1094 
1095 	/*
1096 	 * Realiza una firma XAdES detached (el fichero no se incluirá en la firma). No completa los campos 
1097 	 * no obligatorios del tag 'SignedSignatureProperties':'signaturePolicyIdentifier' y 
1098 	 * 'signatureProductionPlace'.
1099 	 * 
1100 	 * @param manager Dispositivo criptográfico que realizará la firma
1101 	 * @param alias Alias donde se encuentra la clave privada dentro del dispositivo
1102 	 * @param document Documento a firmar. 
1103 	 * @param digitalSignatureAlgorithm Algoritmo de firma
1104 	 * @param reference Referencia a la que apuntará la firma
1105 	 * @param urlTSA URL al servicio de sello de tiempos
1106 	 * @param certStatusRecover Objeto para determinar estado de certificados. Se utiliza
1107 	 * 	a partir del XAdES-C
1108 	 * @param tipoXAdES Tipo de XAdES tal y como se establece en las constantes de la clase
1109 	 * 	<code>EnumFormatoFirma</code>
1110 	 * @param dof Información para construir el tag DataObjectFormat (puede ser null)
1111 	 * @param claimedRoles Roles de la firma
1112 	 * @param returnClassObject Clase del objeto respuesta. Debe ser coincidente con lo indicado
1113 	 * 	en el parámetro tipoXAdES
1114 	 * @return Firma XADES del tipo indicado
1115 	 * @throws LoadingObjectException No ha sido posible cargar la clave privada o el certificado usados
1116 	 *  para realizar la firma
1117 	 * @throws SignatureException No se puede realizar la firma
1118 	 */
1119 	protected static XAdESSignature signDetached (DeviceManager manager, String alias, IDocument document, 
1120 			String reference, TSAData tsaData, ICertStatusRecoverer certStatusRecover, 
1121 			XAdESDetachedSignatureOptions options, EnumFormatoFirma tipoXAdES, Class<?> returnClassObject) 
1122 					throws LoadingObjectException, SignatureException {
1123 		
1124 		logger.debug("[XAdESSignature.signDetached]::Entrada::" + Arrays.asList(new Object[] { manager, alias, document, reference, certStatusRecover, tipoXAdES, tsaData, options, returnClassObject }));
1125 		
1126 		if (options == null) {
1127 			options = new XAdESDetachedSignatureOptions();
1128 		}
1129 		
1130 		// Obtener el certificado en base64
1131 		X509Certificate certificate;
1132 		try {
1133 			logger.debug ("[XAdESSignature.signDetached]::obteniendo el certificado");
1134 			certificate = manager.getCertificate(alias);
1135 		} catch (SearchingException e) {
1136 			logger.info("[XAdESSignature.signDetached]::Error buscando un certificado en el alias'" + alias + "'", e);
1137 			throw new LoadingObjectException ("Error buscando un certificado en el alias'" + alias + "'", e);
1138 		}
1139 		
1140 		if (certificate == null) {
1141 			logger.info("[XAdESSignature.signDetached]::No se ha podido encontrar un certificado en el alias'" + alias + "'");
1142 			throw new LoadingObjectException ("No se ha podido encontrar un certificado en el alias'" + alias + "'");
1143 		}
1144 
1145 		//-- Obtener los datos a firmar
1146 		logger.debug ("[XAdESSignature.signDetached]::obteniendo los datos a firmar");
1147 		DataToSign dataToSign = createDataToSignDetached(document, reference, certStatusRecover, tipoXAdES, 
1148 				options.getDof(), options.getClaimedRoles(), options.getPolicyIdentifier(),
1149 				options.getProductionPlace(), options.getTsaHashingAlgorithm());
1150 		if (dataToSign == null) {
1151 			logger.debug ("[XAdESSignature.signDetached]::El objeto a firmar no es un fichero ni una URL");
1152 			throw new SignatureException ("El objeto a firmar no es un fichero ni una URL");
1153 		}
1154 		
1155 		//-- Firmar
1156 		try {
1157 			logger.debug ("[XAdESSignature.signDetached]::Firmando");
1158 			FirmaXML firma = new FirmaXML();  
1159 			if (tsaData != null) { 
1160 				firma.setTSA(tsaData.getUrl().toString()); 
1161 			}
1162 			Object[] res = firma.signFile(certificate, dataToSign, manager.getPrivateKey(alias), XAdESUtil.getXAdESDigitalSignatureAlgorithm(options.getDigitalSignatureAlgorithm()), null);
1163 			logger.debug ("[XAdESSignature.signDetached]::Firma realizada");
1164 			
1165 			//-- Devolver el tipo adecuado
1166 			Constructor<?> constructor = returnClassObject.getDeclaredConstructor(Document.class);
1167 			return (XAdESSignature)constructor.newInstance((Document) res[0]);
1168 			
1169 		} catch (Exception e) {
1170 			logger.info("[XAdESSignature.signDetached]::No ha sido posible realizar la firma", e);
1171 			throw new SignatureException ("No ha sido posible realizar la firma", e);
1172 		}
1173 		
1174 	}
1175 	
1176 	/*
1177 	 * Realiza una firma XAdES atached (el documento se incluye en la firma). No completa los campos no 
1178 	 * obligatorios del tag 'SignedSignatureProperties':'signaturePolicyIdentifier' y 'signatureProductionPlace' 
1179 	 * 
1180 	 * @param manager Dispositivo criptográfico que realizará la firma
1181 	 * @param alias Alias donde se encuentra la clave privada dentro del dispositivo
1182 	 * @param document Documento a firmar. 
1183 	 * @param tsaData Información de acceso al servicio de sello de tiempos
1184 	 * @param certStatusRecover Objeto para determinar estado de certificados. Se utiliza
1185 	 * 	a partir del XAdES
1186 	 * @param options Opciones de la firma
1187 	 * @param tipoXAdES Tipo de XAdES tal y como se establece en las constantes de la clase
1188 	 * 	<code>EnumFormatoFirma</code>
1189 	 * @param returnClassObject Clase del objeto respuesta. Debe ser coincidente con lo indicado
1190 	 * 	en el parámetro tipoXAdES
1191 	 * @return Firma XADES del tipo indicado
1192 	 * @throws LoadingObjectException No ha sido posible cargar la clave privada o el certificado usados
1193 	 *  para realizar la firma
1194 	 * @throws SignatureException No se puede realizar la firma
1195 	 */
1196 	protected static XAdESSignature signAttached (DeviceManager manager, String alias, IDocument document, 
1197 			TSAData tsaData, ICertStatusRecoverer certStatusRecover, XAdESAttachedSignatureOptions options, 
1198 			EnumFormatoFirma tipoXAdES,	Class<?> returnClassObject) 
1199 					throws XMLDocumentException, LoadingObjectException, SignatureException  {
1200 		
1201 		logger.debug("[XAdESSignature.signAttached]::Entrada::" + Arrays.asList(new Object[] { manager, alias, document, certStatusRecover, tipoXAdES, tsaData, options, returnClassObject }));
1202 		
1203 		if (options == null) {
1204 			options = new XAdESAttachedSignatureOptions();
1205 		}
1206 		
1207 		// Obtener el certificado en base64
1208 		X509Certificate certificate;
1209 		try {
1210 			logger.debug ("[XAdESSignature.signAttached]::obteniendo el certificado");
1211 			certificate = manager.getCertificate(alias);
1212 		} catch (SearchingException e) {
1213 			logger.info("[XAdESSignature.signAttached]::Error buscando un certificado en el alias'" + alias + "'", e);
1214 			throw new LoadingObjectException ("Error buscando un certificado en el alias'" + alias + "'", e);
1215 		}
1216 		
1217 		if (certificate == null) {
1218 			logger.info("[XAdESSignature.signAttached]::No se ha podido encontrar un certificado en el alias'" + alias + "'");
1219 			throw new LoadingObjectException ("No se ha podido encontrar un certificado en el alias'" + alias + "'");
1220 		}
1221 
1222 		//-- Guardar el documento en un fichero temporal (se ha de leer varias veces
1223 		//-- y puede ser un stream de lectura)
1224 		File tempFile;
1225 		try {
1226 			tempFile = saveTemporalFile(document.getInputStream());
1227 		} catch (IOException e) {
1228 			logger.info ("[XAdESSignature.signAttached]::No es posible guardar el fichero temporal con el documento a firmar", e);
1229 			throw new LoadingObjectException ("No es posible guardar el fichero temporal con el documento a firmar", e);
1230 		}
1231 		
1232 		try {
1233 			DocumentBuilder db = getDocumentBuilder ();
1234 			
1235 			//-- Comprobar si el fichero es un XML
1236 			Document documentToSign = null;
1237 			try {
1238 				documentToSign = db.parse(tempFile);
1239 			} catch (SAXException e1) {
1240 				logger.debug ("[XAdESSignature.signAttached]::El fichero no es un XML: " + e1.getMessage());
1241 			} catch (IOException e1) {
1242 				logger.debug ("[XAdESSignature.signAttached]::El fichero no es un XML: " + e1.getMessage());
1243 			}
1244 			
1245 			DataToSign dataToSign;
1246 			if (options.getNodeToSign() != null && documentToSign != null) {
1247 				
1248 				//-- Preparar la firma
1249 				logger.debug ("[XAdESSignature.signAttached]::Se firmará el XML del usuario");
1250 				dataToSign = createDataToSignAtached(documentToSign, options.getNodeToSign(), 
1251 						options.getSignatureParent(), null, certStatusRecover, tipoXAdES, 
1252 						options.getDof(), options.getClaimedRoles(), options.getPolicyIdentifier(), 
1253 						options.getProductionPlace(), options.getTsaHashingAlgorithm());
1254 				
1255 			} else {
1256 				
1257 				logger.debug ("[XAdESSignature.signAttached]::Construir la plantilla por defecto de XAdES");
1258 				
1259 				//-- URI de la codificación (por defecto null)
1260 				URI uri = null;
1261 				
1262 				//-- Obtener la plantilla
1263 				Document doc;
1264 				try {
1265 					doc = db.parse(new Util().getClass().getClassLoader().getResourceAsStream(TEMPLATE_ARANGI_XADES));
1266 				} catch (SAXException e) {
1267 					logger.info("[XAdESSignature.signAttached]::No ha sido posible obtener la plantilla de Arangí-XAdES", e);
1268 					throw new XMLDocumentException ("No ha sido posible obtener la plantilla de Arangí-XAdES", e);
1269 				} catch (IOException e) {
1270 					logger.info("[XAdESSignature.signAttached]::No ha sido posible obtener la plantilla de Arangí-XAdES", e);
1271 					throw new XMLDocumentException ("No ha sido posible obtener la plantilla de Arangí-XAdES", e);
1272 				}
1273 				
1274 				//-- Buscar el elemento documento
1275 				XPathFactory factory = XPathFactory.newInstance();
1276 				XPath xpath = factory.newXPath();
1277 				NodeList signatureNodes;
1278 				try {
1279 					XPathExpression expr = xpath.compile("//*[@Id='" + DEFAULT_ID_TAG_DOCUMENT + "']");
1280 					signatureNodes = (NodeList) expr.evaluate (doc, XPathConstants.NODESET);
1281 				} catch (XPathExpressionException e) {
1282 					logger.info("[XAdESSignature.signAttached]::No ha sido posible obtener el elemento documento dentro de la plantilla", e);
1283 					throw new XMLDocumentException ("No ha sido posible obtener el elemento documento dentro de la plantilla", e);
1284 				}
1285 				Element eDocument = (Element) signatureNodes.item(0);
1286 				
1287 				//-- Añadir el documento
1288 				logger.debug ("[XAdESSignature.signAttached]::Añadir fichero en base64 a la plantilla");
1289 				try {
1290 					eDocument.appendChild(doc.createTextNode(Util.encodeBase64(Util.loadFile(tempFile))));
1291 					uri = new URI (ConstantesXADES.URI_BASE_64);
1292 				} catch (IOException e) {
1293 					logger.info ("[XAdESSignature.signAttached]::No es posible leer el fichero temporal con el documento a firmar", e);
1294 					throw new XMLDocumentException ("No es posible leer el fichero temporal con el documento a firmar", e);
1295 				} catch (URISyntaxException e) {
1296 					//-- No se dará o las clases del mityc estarían mal
1297 					logger.info ("[XAdESSignature.signAttached]::No es posible obtener la URI: " + ConstantesXADES.URI_BASE_64, e);
1298 				}
1299 				
1300 				//-- Preparar la firma. Si es enveloped se firma todo el documento. Si no se firma el tag del documento
1301 				XAdESAttachedNodeToSign nodeToSign = options.getNodeToSign();
1302 				if (nodeToSign == null) {
1303 					nodeToSign = new XAdESAttachedNodeToSignObject(DEFAULT_ID_TAG_DOCUMENT);
1304 				}
1305 				dataToSign = createDataToSignAtached(doc, nodeToSign, null, uri, certStatusRecover, tipoXAdES, 
1306 						options.getDof(), options.getClaimedRoles(), options.getPolicyIdentifier(),
1307 						options.getProductionPlace(), options.getTsaHashingAlgorithm());
1308 				
1309 			}
1310 			
1311 			//-- Firmar
1312 			try {
1313 				FirmaXML firma = new FirmaXML();  
1314 				if (tsaData != null) { 
1315 					firma.setTSA(tsaData.getUrl().toString());
1316 				}
1317 				Object[] res = firma.signFile(certificate, dataToSign, manager.getPrivateKey(alias), XAdESUtil.getXAdESDigitalSignatureAlgorithm(options.getDigitalSignatureAlgorithm()), null);
1318 				
1319 				//-- Devolver el tipo adecuado
1320 				Constructor<?> constructor = returnClassObject.getDeclaredConstructor(Document.class);
1321 				return (XAdESSignature)constructor.newInstance((Document) res[0]);
1322 	
1323 			} catch (Exception e) {
1324 				logger.info("[XAdESSignature.sign]::No ha sido posible realizar la firma", e);
1325 				throw new SignatureException ("No ha sido posible realizar la firma", e);
1326 			}
1327 
1328 		} finally {
1329 			//-- Siempre borrar el fichero temporal
1330 			tempFile.delete();
1331 		}
1332 	}
1333 	
1334 	/*
1335 	 * Añade una Cofirma a la firma XAdES. Realizará una firma de las mismas características que 
1336 	 * la primera que encuentre (attached o dettached).<br><br>
1337 	 * 
1338 	 * @param manager Dispositivo criptográfico que realizará la cofirma
1339 	 * @param alias Alias donde se encuentra la clave privada dentro del dispositivo
1340 	 * @param documentToSign contenido a firmar. El mismo utilizado en la generación de las otras firmas.
1341 	 * @param digitalSignatureAlgorithm Algoritmo de firma
1342 	 * @param urlTSA URL al servicio de sello de tiempos
1343 	 * @param certStatusRecover Objeto para determinar estado de certificados. Se utiliza
1344 	 * 	a partir del XAdES
1345 	 * @param tipoXAdES Tipo de XAdES tal y como se establece en las constantes de la clase
1346 	 * 	<code>EnumFormatoFirma</code>
1347 	 * @param returnClassObject Clase del objeto respuesta. Debe ser coincidente con lo indicado
1348 	 * 	en el parámetro tipoXAdES
1349 	 * @throws SignatureNotFoundException No existe ninguna firma que cofirmar
1350 	 * @throws NoDocumentToSignException El fichero a firmar no existe o es nulo
1351 	 * @throws HashingException Error realizando el hash del documento
1352 	 * @throws LoadingObjectException No ha sido posible cargar la clave privada o el certificado usados
1353 	 *  para realizar la firma
1354 	 * @throws SignatureException No ha sido posible parsear la firma XAdES o no se puede realizar la cofirma
1355 	 * @throws NoCoincidentDocumentException El documento que se quiere firmar no se corresponde con el de
1356 	 * 	la firma XAdES  
1357 	 */
1358 	protected void coSign (DeviceManager manager, String alias, IDocument documentToSign, String digitalSignatureAlgorithm, 
1359 			URL urlTSA, ICertStatusRecoverer certStatusRecover, EnumFormatoFirma tipoXAdES,	
1360 			Class<?> returnClassObject) throws SignatureNotFoundException, NoDocumentToSignException, 
1361 				HashingException, LoadingObjectException, SignatureException, NoCoincidentDocumentException {
1362 		
1363 		logger.debug("[XAdESSignature.coSign]::Entrada::" + Arrays.asList(new Object[] { manager, alias, documentToSign }));
1364 		
1365 		//-- Obtenemos el nodo donde se encuentra la firma. Cogemos la primera, en principio daria igual la elegida 
1366 		// si todas son multifirmas
1367 		String uriXmlNS = "http://www.w3.org/2000/09/xmldsig#";
1368 		NodeList signatureList = xadesDocument.getElementsByTagNameNS(uriXmlNS, "Signature");
1369 		String signatureParent = null;
1370 		Node nodeSignature = null;
1371 		if (signatureList.getLength() < 1) {
1372 			logger.info("[XAdESSignature.coSign]:: No existe ninguna firma en el XAdES");
1373 			throw new SignatureNotFoundException("No existe ninguna firma en el XAdES");
1374 		} else {
1375 			nodeSignature = signatureList.item(0);
1376 			signatureParent = nodeSignature.getParentNode().getLocalName();			
1377 		}
1378 		
1379 		logger.debug("[XAdESSignature.coSign]:: Obtenido el nodo de firma");
1380 		
1381 		//-- Obtenemos la referencia al documento. Suponemos que es la primera com el id que empiece con Reference-ID
1382 		byte[] hashReference = null;
1383 		boolean attached = false;
1384 		XAdESAttachedNodeToSignObject idToSign = null;
1385 		try {
1386 			XMLSignature firmaDocumento = new XMLSignature((Element)nodeSignature, "./");
1387 			SignedInfo signedInfo = firmaDocumento.getSignedInfo();
1388 			for(int i = 0; i < signedInfo.getLength(); i++){
1389 				Reference ref = signedInfo.item(i);
1390 	            if (ref.getId().startsWith("Reference-ID")) {
1391 	            	String uri = ref.getURI();
1392 	            	if (uri.startsWith("#")) {
1393 						// Sera una firma Attached
1394 	            		logger.debug("[XAdESSignature.coSign]:: Se trata de una firma attached");
1395 	            		attached = true;
1396 	            		// Buscar el nodo firmado
1397 	            		idToSign = new XAdESAttachedNodeToSignObject(uri.substring(1, uri.length()));
1398 	            		
1399 					} else {
1400 						// Sera una firma Dettached
1401 						logger.debug("[XAdESSignature.coSign]:: Se trata de una firma detached");
1402 						if (documentToSign == null) {
1403 							
1404 							//-- Si la referencia es un fichero o una URL, ese sera el documentToSign
1405 							if (uri.startsWith("file:/")) {
1406 								logger.debug("[XAdESSignature.coSign]:: Se trata de una firma detached referencia a un fichero: " + uri);
1407 								File file = new File (uri.substring(6));
1408 								if (file.exists()) {
1409 									try {
1410 										documentToSign = new FileDocument(file);
1411 										logger.debug("[XAdESSignature.coSign]:: El fichero existe: " + file);
1412 									} catch (InitDocumentException e) {
1413 										// Ya hemos comprobado que el documento existe
1414 									}
1415 								} else {
1416 									logger.debug("[XAdESSignature.coSign]:: El fichero no existe: " + file);
1417 								}
1418 							} 
1419 							
1420 							if (uri.startsWith("http://") || uri.startsWith("https://")) {
1421 								logger.debug("[XAdESSignature.coSign]:: Se trata de una firma detached referencia a una URL: " + uri);
1422 								try {
1423 									documentToSign = new URLDocument(new URL (uri));
1424 								} catch (InitDocumentException e) {
1425 									logger.info("[XAdESSignature.coSign]:: No es posible conectarse a la URL: " + uri);
1426 								} catch (MalformedURLException e) {
1427 									logger.info("[XAdESSignature.coSign]:: La URL está mal formada: " + uri);
1428 								}
1429 							}
1430 							
1431 							//-- Si no es ni fichero ni URL, entonces si que es un error
1432 							if (documentToSign == null) {
1433 								throw new NoDocumentToSignException("Es necesario proporcionar un documento ya que la referencia a este no es suficiente");
1434 							}
1435 						}
1436 						
1437 						idToSign = new XAdESAttachedNodeToSignObject(uri);
1438 						hashReference = ref.getDigestValue();
1439 					}
1440 				}    
1441 			}
1442 		} catch (XMLSecurityException e) {
1443 			logger.info("[XAdESSignature.coSign]::Error buscando elementos en el fichero XAdES", e);
1444 			throw new SignatureException("Error buscando elementos en el fichero XAdES", e);
1445 		}
1446 		
1447 		//-- Si es un detached comprobamos que el hash del documento que proporcionamos coincide con el de la firma
1448 		if (hashReference != null) {
1449 			logger.debug("[XAdESSignature.coSign]:: La referencia es un path. Comprobamos que los documentos coincidan");
1450 			try {
1451 				byte[] hashDoc = documentToSign.getHash();
1452 				if (!(new String(hashDoc)).equalsIgnoreCase(new String(hashReference))) {
1453 					throw new NoCoincidentDocumentException("El hash del documento proporcionado no coincide con el de la firma existente");
1454 				}
1455 			} catch (HashingException e) {
1456 				throw new HashingException("No se ha podido calcular el hash del documento");
1457 			}
1458 			
1459 		}
1460 		
1461 		DataToSign dataToSign = null;
1462 		if (attached) {
1463 			dataToSign = createDataToSignAtached(xadesDocument, idToSign, null, null, certStatusRecover, tipoXAdES, null, null, null, null, null);			
1464 		} else {
1465 			dataToSign = createDataToSignDetached(documentToSign, idToSign.getIdToSign(), certStatusRecover, tipoXAdES, null, null, null, null, null);
1466 		}
1467 		
1468 		// Obtener el certificado en base64
1469 		X509Certificate certificate;
1470 		try {
1471 			logger.debug ("[XAdESSignature.coSign]::obteniendo el certificado");
1472 			certificate = manager.getCertificate(alias);
1473 		} catch (SearchingException e) {
1474 			logger.info("[XAdESSignature.coSign]::No se ha podido encontrar un certificado en el alias'" + alias + "'", e);
1475 			throw new LoadingObjectException ("No se ha podido encontrar un certificado en el alias'" + alias + "'", e);
1476 		}
1477 		
1478 		try {
1479 			FirmaXML firma = new FirmaXML();  
1480 			if (urlTSA != null) { firma.setTSA(urlTSA.toString()); }
1481 			
1482 			logger.debug("[XAdESSignature.coSign]:: Realizando la firma");
1483 			Object[] res = firma.signFile(certificate, dataToSign, manager.getPrivateKey(alias), XAdESUtil.getXAdESDigitalSignatureAlgorithm(digitalSignatureAlgorithm), null);
1484 			Constructor<?> constructor = returnClassObject.getDeclaredConstructor(Document.class);
1485 			XAdESSignature xades = (XAdESSignature)constructor.newInstance((Document) res[0]);
1486 			logger.debug("[XAdESSignature.coSign]:: Firma realizada");
1487 			if (attached) {
1488 				//-- "Refrescar" el document XAdES
1489 				xadesDocument = xades.getDOM();
1490 			} else {
1491 				logger.debug("[XAdESSignature.coSign]:: Añadimos la nueva firma al XAdES");
1492 				//-- Extraer la firma y añadirla al documento original
1493 				NodeList signaturesList = xades.getDOM().getElementsByTagNameNS(uriXmlNS, "Signature");
1494 				//-- Sólo existe una firma que acabamos de crear
1495 				Node signature = signaturesList.item(0);
1496 				
1497 				Element rootDocument = xadesDocument.getDocumentElement();
1498 				if (rootDocument.isEqualNode(xadesDocument.getElementsByTagNameNS(uriXmlNS, "Signature").item(0))) {
1499 					logger.debug("[XAdESSignature.coSign]:: La firma es nodo raiz. Cramos un nuevo nodo raiz Signatures");
1500 					// Si el XML con el XAdES tiene como elemento raiz Signature se crea otro raiz llamado 
1501 					// Signatures para ir añadiendo las firmas
1502 					DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1503 					DocumentBuilder builder = dbf.newDocumentBuilder();
1504 					
1505 					// Create an empty document
1506 					Document doc = builder.newDocument();
1507 					
1508 					Element root = doc.createElement("Signatures");
1509 					doc.appendChild(root);
1510 					
1511 					// Add a copy of the nodes from existing document
1512 					Node oldSignature = doc.importNode((xadesDocument.getElementsByTagNameNS(uriXmlNS, "Signature").item(0)), true);
1513 					root.appendChild(oldSignature);
1514 					Node newSignature = doc.importNode(signature, true);
1515 					root.appendChild(newSignature);
1516 					
1517 					xadesDocument = doc;
1518 					
1519 				} else {
1520 					// Si el XML con el XAdES NI tiene como elemento raiz Signature se busca el nodo
1521 					// padre de la primera firma y se añade allí la nueva
1522 					NodeList siganturesList = xadesDocument.getElementsByTagNameNS(uriXmlNS, "Signature");
1523 					Node parentNode = siganturesList.item(0).getParentNode();
1524 					Node newSignature = xadesDocument.importNode(signature, true);
1525 					parentNode.appendChild(newSignature);
1526 				}
1527 
1528 			}
1529 
1530 		} catch (Exception e) {
1531 			logger.info("[XAdESSignature.coSign]::No ha sido posible realizar la firma", e);
1532 			throw new SignatureException ("No ha sido posible realizar la firma", e);
1533 		}
1534 	}
1535 	
1536 	/*
1537 	 * Parsea la fecha en formato xsd:timeFormat
1538 	 */
1539 	protected static Date getXsdDateTimeParse(String sDate) throws ParseException {
1540 		
1541 		Date date = xsdDateTimeFormat.parse(sDate.substring (0,19));
1542 //		int offset = Integer.parseInt(sDate.substring (21,22));
1543 		GregorianCalendar cal = new GregorianCalendar();
1544 		cal.setTime(date);
1545 //		cal.add(Calendar.HOUR_OF_DAY, offset);
1546 		return cal.getTime();
1547 	}
1548 
1549 	//-- TEMPORAL: Métodos copiados de la implementación de FirmaXML del MITyC. Se
1550 	//-- utilizarán para promocionar las firmas XAdES hasta que se implementen éstas
1551 	//-- dentro de la librería.
1552 	
1553     /**
1554      * Este método añade la implementación para XADES-T
1555      * @param doc Documento de firma con formato XADES-BES
1556      * @param firmaID Identificador del nodo de firma
1557      * @param selloTiempo Respuesta del servidor TSA con el sello de tiempo en formato binario
1558      * @return Documento de firma con formato XADES-T
1559      * @throws Exception
1560      */
1561     protected static Document addXadesT(Element firma, String firmaID, byte[] selloTiempo,
1562     		String namespace) throws Exception    {    	 	
1563 
1564     	Document doc = firma.getOwnerDocument();
1565     	Element elementoPrincipal = null ;
1566     	NodeList nodos = firma.getElementsByTagNameNS(DEFAULT_XADES_SCHEMA_URI, ConstantesXADES.QUALIFYING_PROPERTIES);
1567     	if(nodos.getLength() != 0)
1568     		elementoPrincipal = (Element)nodos.item(0);
1569     	else
1570     		throw new Exception("El XML no parece un XAdES") ;
1571 
1572     	Element propiedadesElementosNoFirmados =
1573     		doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.UNSIGNED_PROPERTIES);
1574     	
1575     	// Creamos los atributos de UnSignedProperties
1576     	Attr propiedadesNoFirmadasId = doc.createAttributeNS(null, ConstantesXADES.ID);
1577     	propiedadesNoFirmadasId.setValue(UtilidadTratarNodo.newID(doc, 
1578     			firmaID  + ConstantesXADES.GUION_UNSIGNED_PROPERTIES));
1579     	NamedNodeMap atributosSinFirmarPropiedadesElemento =
1580     		propiedadesElementosNoFirmados.getAttributes();
1581     	atributosSinFirmarPropiedadesElemento.setNamedItem(propiedadesNoFirmadasId);
1582 
1583     	Element propiedadesSinFirmarFirmaElementos =
1584     		doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.UNSIGNED_SIGNATURE_PROPERTIES);
1585     	
1586     	// Se buscan otros sellos de tiempo en la firma y se les asigna una Id si no la tienen
1587     	NodeList sellosPreexistentes = doc.getElementsByTagNameNS(DEFAULT_XADES_SCHEMA_URI, ConstantesXADES.SIGNATURE_TIME_STAMP);
1588     	int numSellos = sellosPreexistentes.getLength();
1589     	ArrayList<String> idNodoSelloTiempo = new ArrayList<String>();
1590     	for (int i = 0; i < numSellos; ++i) {
1591     		Element sello = (Element) sellosPreexistentes.item(i);
1592     		String selloId = sello.getAttribute(ConstantesXADES.ID);
1593     		if (selloId == null) {
1594     			Attr informacionElementoSigTimeStamp = doc.createAttributeNS(null, ConstantesXADES.ID);
1595     			selloId = UtilidadTratarNodo.newID(doc, ConstantesXADES.SELLO_TIEMPO);
1596     	    	informacionElementoSigTimeStamp.setValue(selloId);
1597     	    	sello.getAttributes().setNamedItem(informacionElementoSigTimeStamp);
1598     		}
1599     		// Se almacena su nombre de Id por si es preciso referenciarlos
1600     		idNodoSelloTiempo.add(selloId); 		
1601     	}
1602     	
1603     	// Se crea el nodo de sello de tiempo
1604     	Element tiempoSelloElementoFirma =
1605     		doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.SIGNATURE_TIME_STAMP);
1606 	
1607     	// Se escribe una Id única
1608     	Attr informacionElementoSigTimeStamp = doc.createAttributeNS(null, ConstantesXADES.ID);
1609     	String idSelloTiempo = UtilidadTratarNodo.newID(doc, ConstantesXADES.SELLO_TIEMPO);
1610     	informacionElementoSigTimeStamp.setValue(idSelloTiempo);
1611     	idNodoSelloTiempo.add(idSelloTiempo);
1612     	tiempoSelloElementoFirma.getAttributes().setNamedItem(informacionElementoSigTimeStamp);
1613 
1614     	// Se incluye un nodo que referencia a la Id de SignatureValue
1615     	if (ConstantesXADES.SCHEMA_XADES_111.equals(DEFAULT_XADES_SCHEMA_URI) 
1616     			|| ConstantesXADES.SCHEMA_XADES_122.equals(DEFAULT_XADES_SCHEMA_URI)) {
1617     		
1618     		String nombreNodoUri = null;
1619     		String tipoUri = null;
1620     		if (ConstantesXADES.SCHEMA_XADES_111.equals(DEFAULT_XADES_SCHEMA_URI)) {
1621     			nombreNodoUri = ConstantesXADES.HASH_DATA_INFO;
1622     			tipoUri = ConstantesXADES.URI_MINUS;
1623     		} else {
1624     			nombreNodoUri = ConstantesXADES.INCLUDE;
1625     			tipoUri = ConstantesXADES.URI_MAYUS;
1626     		}
1627     		
1628     		ArrayList<Element> listElements = UtilidadTratarNodo.obtenerNodos(firma, 2, new NombreNodo(ConstantesXADES.SCHEMA_DSIG, ConstantesXADES.SIGNATURE_VALUE));
1629     		if (listElements.size() != 1) {
1630     			logger.info("No se encuentra el tag de firma en el XML"); 
1631           		throw new Exception("No se encuentra el tag de firma en el XML");
1632     		}
1633     		String idSignatureValue = listElements.get(0).getAttribute(ConstantesXADES.ID);
1634 
1635     		
1636         	Element informacionElementoHashDatos = doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + nombreNodoUri);
1637     		
1638     		Attr informacionElementoHashDatosUri = doc.createAttributeNS(null, tipoUri);
1639     		informacionElementoHashDatosUri.setValue(ConstantesXADES.ALMOHADILLA + idSignatureValue);
1640 
1641     		NamedNodeMap informacionAtributosElementoHashDatos = informacionElementoHashDatos.getAttributes();
1642     		informacionAtributosElementoHashDatos.setNamedItem(informacionElementoHashDatosUri);
1643 
1644     		tiempoSelloElementoFirma.appendChild(informacionElementoHashDatos) ;
1645     	}
1646     	
1647     	// Se crea el nodo canonicalizationMethod en los esquemas 1.2.2 y 1.3.2
1648     	if (!ConstantesXADES.SCHEMA_XADES_111.equals(DEFAULT_XADES_SCHEMA_URI)) {
1649     		Element canonicalizationElemento = doc.createElementNS(ConstantesXADES.SCHEMA_DSIG, xmldsigNS + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.CANONICALIZATION_METHOD);		
1650     		Attr canonicalizationAttribute = doc.createAttributeNS(null, ConstantesXADES.ALGORITHM);
1651     		canonicalizationAttribute.setValue(Transforms.TRANSFORM_C14N_OMIT_COMMENTS);
1652     		canonicalizationElemento.getAttributes().setNamedItem(canonicalizationAttribute);
1653 
1654     		tiempoSelloElementoFirma.appendChild(canonicalizationElemento);
1655     	}
1656 		
1657 		// Se crea el nodo del sello de tiempo
1658 		Element tiempoSelloEncapsulado =
1659     		doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.ENCAPSULATED_TIME_STAMP);
1660 
1661     	tiempoSelloEncapsulado.appendChild(
1662     			doc.createTextNode(new String(Base64Coder.encode(selloTiempo))));
1663     	Attr tiempoSelloEncapsuladoId = doc.createAttributeNS(null, ConstantesXADES.ID);
1664     	String idEncapsulated = UtilidadTratarNodo.newID(doc, ConstantesXADES.SELLO_TIEMPO_TOKEN);
1665     	tiempoSelloEncapsuladoId.setValue(idEncapsulated);
1666     	tiempoSelloEncapsulado.getAttributes().setNamedItem(tiempoSelloEncapsuladoId);
1667     	
1668     	
1669     	tiempoSelloElementoFirma.appendChild(tiempoSelloEncapsulado);
1670 
1671     	propiedadesSinFirmarFirmaElementos.appendChild(tiempoSelloElementoFirma);
1672     	propiedadesElementosNoFirmados.appendChild(propiedadesSinFirmarFirmaElementos);
1673     	elementoPrincipal.appendChild(propiedadesElementosNoFirmados);
1674     	return doc;
1675     }
1676 
1677     /**
1678      * Este método añade la implementacion para XADES-C
1679      */
1680     protected static Document addXadesC(Element firma, ArrayList<RespYCerts> respuestasFirma,
1681     		ArrayList<RespYCerts> respuestasSello, XAdESSchemas schema, String algDigestXML, 
1682     		String namespace) throws Exception {
1683     	Document doc = firma.getOwnerDocument();
1684     	// Recogemos el nodo UnsignedSignatureProperties del cual dependen los nodos
1685     	// que hay que añadir para completar la firma XADES-C
1686     	Element elementoPrincipal = null ;
1687 
1688 		String tipoUri = null;
1689 		if (ConstantesXADES.SCHEMA_XADES_111.equals(DEFAULT_XADES_SCHEMA_URI)) {
1690 			tipoUri = ConstantesXADES.URI_MINUS;
1691 		} else {
1692 			tipoUri = ConstantesXADES.URI_MAYUS;
1693 		}
1694     	
1695     	NodeList nodos = firma.getElementsByTagNameNS(DEFAULT_XADES_SCHEMA_URI, ConstantesXADES.UNSIGNED_SIGNATURE_PROPERTIES);
1696     	if(nodos.getLength() != 0)
1697     	{
1698     		elementoPrincipal = (Element)nodos.item(0);
1699         }
1700         else
1701         {
1702         	throw new Exception("El XML no parece un XAdES") ;
1703         }
1704         
1705         // Aqui vienen las llamadas para los certificados
1706         Element certificadosElementosFirma =
1707                 doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.COMPLETE_CERTIFICATE_REFS);
1708         Element revocacionesElementoFirma =
1709             doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.COMPLETE_REVOCATION_REFS);
1710 
1711         if(respuestasFirma != null && !respuestasFirma.isEmpty()) {
1712         	
1713         	// Se le agrega una Id única
1714         	Attr informacionElementoCertRef = doc.createAttributeNS(null, ConstantesXADES.ID);
1715         	String idNodoCertificateRefs = UtilidadTratarNodo.newID(doc, ConstantesXADES.COMPLETE_CERTIFICATE_REFS);
1716         	informacionElementoCertRef.setValue(idNodoCertificateRefs);
1717         	certificadosElementosFirma.getAttributes().setNamedItem(informacionElementoCertRef);
1718         	
1719         	Element elementoCertRefs =
1720                 doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.CERT_REFS);
1721 
1722         	certificadosElementosFirma.appendChild(elementoCertRefs);
1723         	
1724         	Set<X509Certificate> setCertificadosIncluidos = new HashSet<X509Certificate>();
1725         	ArrayList[] listas = new ArrayList[] { respuestasFirma, respuestasSello };
1726         	boolean primero = true;
1727         	for (int x=0;x<2;x++) {
1728         	
1729         		ArrayList<RespYCerts> respuestas = listas[x];
1730 	        	
1731 	        	int i = -1;
1732 	        	for (RespYCerts respYCerts : respuestas) {
1733 	        		i++;
1734 	        		
1735 	            	// Se agrega una id al certificado
1736 	            	String idNueva = UtilidadTratarNodo.newID(doc, ConstantesXADES.LIBRERIAXADES_CERT_PATH);
1737 	            	respuestas.get(i).setIdCertificado(idNueva);
1738 	            	
1739 	            	if (primero) {
1740 	            		primero = false;
1741 	            		continue;
1742 	            	}
1743 	        		
1744 	        		X509Certificate firmaCertificado = respYCerts.getCertstatus().getCertificate();
1745 	        		if (setCertificadosIncluidos.contains(firmaCertificado)) {
1746 	        			continue;
1747 	        		}
1748 	        		setCertificadosIncluidos.add(firmaCertificado);
1749 	        		
1750 	        		Element elementCertRef = doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.CERT);
1751 	        		
1752 	        		// Creamos los atributos de UnSignedProperties
1753 	            	Attr uris = doc.createAttributeNS(null, tipoUri);
1754 					// AppPerfect: Falso positivo. No son expresiones constantes
1755 	            	idNueva = UtilidadTratarNodo.newID(doc, ConstantesXADES.LIBRERIAXADES_CERT_PATH);
1756 	            	uris.setValue( ConstantesXADES.ALMOHADILLA + idNueva );
1757 	            	respuestas.get(i).setIdCertificado(idNueva);
1758 	            	NamedNodeMap atributosURI = elementCertRef.getAttributes();
1759 	            	atributosURI.setNamedItem(uris);
1760 	
1761 	    	        Element resumenElementoCert = doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.CERT_DIGEST);
1762 	
1763 	    	        // Creamos el xades:DigestMethod
1764 	    	        Element metodoResumenElemento = doc.createElementNS(ConstantesXADES.SCHEMA_DSIG, xmldsigNS + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.DIGEST_METHOD);
1765 	
1766 	    	        // Creamos los atributos de DigestMethod
1767 	    	        Attr propiedadesFirmaAlgoritmo = doc.createAttributeNS(null, ConstantesXADES.ALGORITHM);
1768 	    	        propiedadesFirmaAlgoritmo.setValue(algDigestXML);
1769 	    	        NamedNodeMap cualidadesMetodoResumenElemento =
1770 	    	                metodoResumenElemento.getAttributes();
1771 	    	        cualidadesMetodoResumenElemento.setNamedItem(propiedadesFirmaAlgoritmo);
1772 	
1773 	    	        // Creamos el xades:DigestValue
1774 	    	        String resumenCertificado = ConstantesXADES.CADENA_VACIA;
1775 	    	        try
1776 	    	        {
1777 	        			MessageDigest resumenCertificadoTemp = UtilidadFirmaElectronica.getMessageDigest(algDigestXML);
1778 	        			if (resumenCertificadoTemp == null)
1779 	        	        	throw new Exception("No se ha podido realizar el digest");
1780 	    	            byte[] resumenMensajeByte =resumenCertificadoTemp.digest(firmaCertificado.getEncoded());
1781 	    	            resumenCertificado = new String(Base64Coder.encode(resumenMensajeByte));
1782 	    	        } catch (CertificateEncodingException e) {
1783 	    	        	logger.error(e);
1784 	    	        	throw new Exception("Error obteniendo la huella del certificado");				
1785 	    	        }
1786 	
1787 	    	        Element elementDigestValue =
1788 	    	                doc.createElementNS(ConstantesXADES.SCHEMA_DSIG, xmldsigNS + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.DIGEST_VALUE);
1789 	    	        elementDigestValue.appendChild(
1790 	    	                doc.createTextNode(resumenCertificado));
1791 	
1792 	    	        // Creamos el xades:IssuerSerial
1793 	    	        Element elementoEmisorSerial =
1794 	    	                doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.ISSUER_SERIAL);
1795 	    	        // Creamos el xades:X509IssuerName
1796 	    	        Element elementoX509EmisorNombre =
1797 	    	                doc.createElementNS(ConstantesXADES.SCHEMA_DSIG, xmldsigNS + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.X_509_ISSUER_NAME);
1798 	    	        elementoX509EmisorNombre.appendChild(
1799 	    	                doc.createTextNode(firmaCertificado.getIssuerX500Principal().getName()));
1800 	
1801 	    	        // Creamos el xades:X509SerialNumber
1802 	    	        Element elementoX509NumeroSerial =
1803 	    	                doc.createElementNS(ConstantesXADES.SCHEMA_DSIG, xmldsigNS + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.X_509_SERIAL_NUMBER);
1804 	    	        elementoX509NumeroSerial.appendChild(
1805 	    	                doc.createTextNode(firmaCertificado.getSerialNumber().toString()));
1806 	
1807 	    	        //Add references
1808 	    	        elementoEmisorSerial.appendChild(elementoX509EmisorNombre);
1809 	    	        elementoEmisorSerial.appendChild(elementoX509NumeroSerial);
1810 	
1811 	    	        resumenElementoCert.appendChild(metodoResumenElemento);
1812 	    	        resumenElementoCert.appendChild(elementDigestValue);
1813 	
1814 	    	        elementCertRef.appendChild(resumenElementoCert);
1815 	    	        elementCertRef.appendChild(elementoEmisorSerial);
1816 	
1817 	    	        elementoCertRefs.appendChild(elementCertRef);
1818 	        	}
1819         	}
1820         }
1821 
1822     	
1823     	
1824     	Element elementOCSPRef = null;
1825     	String tiempoRespuesta = null;
1826     	byte[] mensajeRespuesta = null;
1827     	
1828         if(respuestasFirma != null && !respuestasFirma.isEmpty()) {
1829         	
1830         	// Se le agrega una Id única
1831         	Attr informacionElementoCertRef = doc.createAttributeNS(null, ConstantesXADES.ID);
1832         	String idNodoRevocationRefs = UtilidadTratarNodo.newID(doc, ConstantesXADES.COMPLETE_REVOCATION_REFS);
1833         	informacionElementoCertRef.setValue(idNodoRevocationRefs);
1834         	revocacionesElementoFirma.getAttributes().setNamedItem(informacionElementoCertRef);
1835         	
1836         	int nOCSPRefs = 0;
1837         	int nCRLRefs = 0;
1838         	
1839             // Construye el valor de la respuesta del servidor OCSP
1840             // bajo el nodo completo de la referencia de la revocación
1841         	Element elementOCSPRefs =
1842                 doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.OCSP_REFS);
1843         	CRLRefs elementCRLRefs = new CRLRefs(schema); 
1844         	
1845         	Set<X509Certificate> setCertificadosIncluidos = new HashSet<X509Certificate>();
1846         	ArrayList[] listas = new ArrayList[] { respuestasFirma, respuestasSello };
1847         	for (int x=0;x<2;x++) {
1848         	
1849         		ArrayList<RespYCerts> respuestas = listas[x];
1850 	        	
1851 	        	for (RespYCerts respYCerts : respuestas) {
1852 	        		// que no se repitan
1853 	        		X509Certificate firmaCertificado = respYCerts.getCertstatus().getCertificate();
1854 	        		if (setCertificadosIncluidos.contains(firmaCertificado)) {
1855 	        			continue;
1856 	        		}
1857 	        		setCertificadosIncluidos.add(firmaCertificado);
1858 	        		
1859 	        		ICertStatus certStatus = respYCerts.getCertstatus();
1860 	        		if (certStatus instanceof IOCSPCertStatus) {
1861 	        			nOCSPRefs++;
1862 	        			IOCSPCertStatus respOcsp = (IOCSPCertStatus) certStatus;
1863 	
1864 		        		tiempoRespuesta = UtilidadFechas.formatFechaXML(respOcsp.getResponseDate());
1865 		        		IOCSPCertStatus.TYPE_RESPONDER tipoResponder = respOcsp.getResponderType();
1866 		        		String valorResponder = respOcsp.getResponderID();
1867 		        		mensajeRespuesta = respOcsp.getEncoded();
1868 		
1869 		        		elementOCSPRef = doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.OCSP_REF);
1870 		        		
1871 		        		// Creamos los atributos de UnSignedProperties
1872 		        		String idNueva = UtilidadTratarNodo.newID(doc, ConstantesXADES.OCSP);
1873 		        		respYCerts.setIdRespStatus(idNueva);
1874 		
1875 		            	Element identificadorElementoOCSP = doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.OCSP_IDENTIFIER);
1876 		            	Attr uris = doc.createAttributeNS(null, tipoUri);
1877 		            	uris.setValue( ConstantesXADES.ALMOHADILLA + idNueva );
1878 		            	NamedNodeMap atributosURI = identificadorElementoOCSP.getAttributes();
1879 		            	atributosURI.setNamedItem(uris);
1880 		
1881 		        		// Creamos el xades:DigestMethod
1882 		        		Element elementoRespondedorId = doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.RESPONDER_ID);
1883 		
1884 		        		
1885 		        		Element responderFinal = elementoRespondedorId;
1886 		        		if (!(ConstantesXADES.SCHEMA_XADES_111.equals(DEFAULT_XADES_SCHEMA_URI)) && !(ConstantesXADES.SCHEMA_XADES_122.equals(DEFAULT_XADES_SCHEMA_URI))) {
1887 		        			Element hijo = null;
1888 		        			if (tipoResponder.equals(IOCSPCertStatus.TYPE_RESPONDER.BY_NAME)) {
1889 		        				hijo = doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.BY_NAME);
1890 		        			}
1891 		        			else {
1892 		        				hijo = doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.BY_KEY);
1893 		        			}
1894 		        			// TODO: tener en cuenta que podria no ser ninguno de estos valores en un futuro
1895 		            		elementoRespondedorId.appendChild(hijo);
1896 		            		responderFinal = hijo;
1897 		        		}
1898 		        		responderFinal.appendChild(doc.createTextNode(valorResponder));
1899 		    			
1900 		
1901 		        		Element elementoProdujoEn = doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.PRODUCE_AT);
1902 		
1903 		
1904 		        		elementoProdujoEn.appendChild(doc.createTextNode(tiempoRespuesta));
1905 		
1906 		        		identificadorElementoOCSP.appendChild(elementoRespondedorId);
1907 		        		identificadorElementoOCSP.appendChild(elementoProdujoEn);
1908 		        		Element valorYResumenElemento = doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.DIGEST_ALG_AND_VALUE);
1909 		
1910 		        		// Creamos el xades:DigestMethod
1911 		        		Element metodoResumenElemento = doc.createElementNS(ConstantesXADES.SCHEMA_DSIG, xmldsigNS + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.DIGEST_METHOD);
1912 		
1913 		        		// Creamos los atributos de DigestMethod
1914 		        		Attr propiedadesAlgoritmoFirmado = doc.createAttributeNS(null, ConstantesXADES.ALGORITHM);
1915 		        		propiedadesAlgoritmoFirmado.setValue(algDigestXML);
1916 		        		NamedNodeMap atributosMetodoResumenElemento = metodoResumenElemento.getAttributes();
1917 		        		atributosMetodoResumenElemento.setNamedItem(propiedadesAlgoritmoFirmado);
1918 		
1919 		        		// Creamos el xades:DigestValue
1920 		        		// El mensaje de la respuesta es el OCSPResponse
1921 		        		String digestCertificado =ConstantesXADES.CADENA_VACIA;
1922 	        			MessageDigest resumenCertificadoTemp = UtilidadFirmaElectronica.getMessageDigest(algDigestXML);
1923 	        			if (resumenCertificadoTemp == null)
1924 	        				throw new Exception("No se ha podido generar el digest");
1925 	        			byte[] resumenMensajeByte = resumenCertificadoTemp.digest(mensajeRespuesta);
1926 	        			digestCertificado = new String(Base64Coder.encode(resumenMensajeByte));
1927 		
1928 		        		Element valorResumenElemento = doc.createElementNS(ConstantesXADES.SCHEMA_DSIG, xmldsigNS + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.DIGEST_VALUE);
1929 		
1930 		        		valorResumenElemento.appendChild(doc.createTextNode(digestCertificado));
1931 		
1932 		        		valorYResumenElemento.appendChild(metodoResumenElemento);
1933 		        		valorYResumenElemento.appendChild(valorResumenElemento);
1934 		
1935 		        		elementOCSPRef.appendChild(identificadorElementoOCSP);
1936 		        		elementOCSPRef.appendChild(valorYResumenElemento);
1937 		
1938 		        		elementOCSPRefs.appendChild(elementOCSPRef);
1939 	        		}
1940 	        		else if (certStatus instanceof IX509CRLCertStatus) {
1941 	        			nCRLRefs++;
1942 	        			IX509CRLCertStatus respCRL = (IX509CRLCertStatus) certStatus;
1943 	        			try {
1944 							CRLRef crlRef = new CRLRef(schema, algDigestXML, respCRL.getX509CRL());
1945 	
1946 							String idNueva = UtilidadTratarNodo.newID(doc, ConstantesXADES.CRL);
1947 							crlRef.getCrlIdentifier().setUri(ConstantesXADES.ALMOHADILLA + idNueva);
1948 							respYCerts.setIdRespStatus(idNueva);
1949 			
1950 							elementCRLRefs.addCRLRef(crlRef);
1951 	        			} catch (InvalidInfoNodeException ex) {
1952 			    			throw new Exception("No se pudo construir las referencias a CRLs", ex);
1953 						}
1954 	        		}
1955 	        	}
1956         	}
1957 
1958         	if (nCRLRefs > 0) {
1959         		try {
1960 					Element el = elementCRLRefs.createElement(doc, xmldsigNS, namespace);
1961 					revocacionesElementoFirma.appendChild(el);
1962 				} catch (InvalidInfoNodeException ex) {
1963 	    			throw new Exception("No se pudo construir las referencias a CRLs", ex);
1964 				}
1965         	}
1966         	
1967         	if (nOCSPRefs > 0)
1968             	revocacionesElementoFirma.appendChild(elementOCSPRefs);
1969         	
1970         }
1971         
1972         elementoPrincipal.appendChild(certificadosElementosFirma);
1973         elementoPrincipal.appendChild(revocacionesElementoFirma);
1974 
1975         return doc;
1976     }
1977 
1978 	/**
1979      * Este metodo añade la implementación del sello de tiempo de tipo 1 (implícito) para 
1980      * XADES-X según los esquemas 1.2.2 y 1.3.2.
1981      * Los elementos sobre los que se calcula el sello son los siguientes:
1982 	 * 		- SignatureValue
1983 	 * 		- SignatureTimestamp
1984 	 * 		- CompleteCertificateRefs
1985 	 * 		- CompleteRevocationRefs
1986 	 * 	Opcionalmente en el esquema 1.2.2 y 1.3.2:
1987 	 * 		- AttributeCertificateRefs
1988 	 * 		- AttributeRevocationRefs
1989 	 * 
1990      * @param Element UnsignedSignatureProperties Nodo a partir del cual se añade el nodo SigAndRefsTimeStamp
1991      * @param servidorTSA Servidor RSA
1992      * @param algoritmoTSA Algoritmo de hash
1993      * @param namespace Espacio de nombres
1994      * @return Documento de firma con formato XADES-X
1995      * @throws Exception En caso de error
1996      */
1997     protected static Document addXadesX(Element unsignedSignatureProperties, URL servidorTSA, 
1998     		String algoritmoTSA, String namespace) throws Exception {
1999     	
2000     	// Se obtiene el documento que contiene al nodo UnsignedSignatureProperties
2001     	Document doc = unsignedSignatureProperties.getOwnerDocument();
2002     	
2003     	// Se crea el nodo SigAndRefsTimeStamp
2004         Element sigAndRefsTimeStampElement =
2005         	doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.SIG_AND_REFS_TIME_STAMP);
2006         
2007         // Se escribe una Id única
2008     	Attr informacionElementoSigTimeStamp = doc.createAttributeNS(null, ConstantesXADES.ID);
2009     	String idSelloTiempo = UtilidadTratarNodo.newID(doc, ConstantesXADES.SELLO_TIEMPO);
2010     	informacionElementoSigTimeStamp.setValue(idSelloTiempo);
2011     	ArrayList<String> idNodoSelloTiempo = new ArrayList<String>();
2012     	idNodoSelloTiempo.add(idSelloTiempo);
2013     	sigAndRefsTimeStampElement.getAttributes().setNamedItem(informacionElementoSigTimeStamp);
2014         
2015         // Se coloca el nodo creado al final del nodo UnsignedSignatureProperties
2016         unsignedSignatureProperties.appendChild(sigAndRefsTimeStampElement);
2017         
2018         return addXadesX(unsignedSignatureProperties, sigAndRefsTimeStampElement, servidorTSA, algoritmoTSA, namespace);
2019     }
2020     
2021 	/**
2022      * Este metodo añade la implementación del sello de tiempo de tipo 1 (implícito) para 
2023      * XADES-X según los esquemas 1.2.2 y 1.3.2.
2024      * Los elementos sobre los que se calcula el sello son los siguientes:
2025 	 * 		- SignatureValue
2026 	 * 		- SignatureTimestamp
2027 	 * 		- CompleteCertificateRefs
2028 	 * 		- CompleteRevocationRefs
2029 	 * 	Opcionalmente en el esquema 1.2.2 y 1.3.2:
2030 	 * 		- AttributeCertificateRefs
2031 	 * 		- AttributeRevocationRefs
2032 	 * 
2033      * @param unsignedSignatureProperties Nodo a partir del cual se añade el nodo SigAndRefsTimeStamp
2034      * @param sigAndRefsTimeStampElement Elemento en el que se incluye el sello
2035      * @param servidorTSA Servidor RSA
2036      * @param algoritmoTSA Algoritmo de hash
2037      * @param namespace Espacio de nombres
2038      * @return Documento de firma con formato XADES-X
2039      * @throws Exception En caso de error
2040      */
2041     protected static Document addXadesX(Element unsignedSignatureProperties, Element sigAndRefsTimeStampElement,
2042     		URL servidorTSA, String algoritmoTSA, String namespace) throws Exception {
2043     	
2044     	// Se obtiene el formato de la constante URI en función del esquema
2045 		String tipoUri = null;
2046 		String nombreNodoUri = null;
2047 		if (ConstantesXADES.SCHEMA_XADES_111.equals(DEFAULT_XADES_SCHEMA_URI)){
2048 			nombreNodoUri = ConstantesXADES.HASH_DATA_INFO;
2049 			tipoUri = ConstantesXADES.URI_MINUS;
2050 		} else {
2051 			nombreNodoUri = ConstantesXADES.INCLUDE;
2052 			tipoUri = ConstantesXADES.URI_MAYUS;
2053 		}
2054     	
2055     	// Se obtiene el documento que contiene al nodo UnsignedSignatureProperties
2056     	Document doc = unsignedSignatureProperties.getOwnerDocument();
2057     	
2058     	// Se obtiene el nodo Signature que contiene al nodo UnsignedSignatureProperties (es el 4º padre, según esquema XAdES)
2059     	Node padre = unsignedSignatureProperties.getParentNode();
2060     	for (int i = 0; i < 3; ++i) {
2061     		if (padre != null)
2062     			padre = padre.getParentNode();
2063     		else
2064     			// No se encuentra el nodo Signature
2065     			throw new Exception("No se encuentra el nodo signature");
2066     	}
2067     	
2068     	Element signatureElement = null;
2069     	if (padre != null && ConstantesXADES.SIGNATURE.equals(padre.getLocalName()))
2070     		signatureElement = (Element)padre;
2071     	else
2072     		// No se encuentra el nodo Signature
2073     		throw new Exception("No se encuentra el nodo signature");
2074     	 
2075         
2076         // Se obtiene el listado de elementos de un sello de tiempo XAdES X de tipo 1
2077         ArrayList<Element> elementosSelloX = null;
2078         try {
2079 			elementosSelloX = UtilidadXadesX.obtenerListadoXADESX1imp(DEFAULT_XADES_SCHEMA_URI, signatureElement, sigAndRefsTimeStampElement);
2080 		} catch (BadFormedSignatureException e) {
2081 			throw new Exception(e.getMessage(), e);
2082 		} catch (FirmaXMLError e) {
2083 			throw new Exception(e.getMessage(), e);
2084 		}
2085 		
2086 		// Se añaden nodos de referencia a los nodos obtenidos para el cálculo del sello (sólo para esquemas 1.2.2 y 1.1.1)
2087 		if (ConstantesXADES.SCHEMA_XADES_111.equals(DEFAULT_XADES_SCHEMA_URI) ||
2088 				ConstantesXADES.SCHEMA_XADES_122.equals(DEFAULT_XADES_SCHEMA_URI)) {
2089 			// Se obtienen las Ids de los nodos del sello de tiempo X
2090 			ArrayList<String> elementosIdSelloX = UtilidadTratarNodo.obtenerIDs(elementosSelloX);
2091 			
2092 			// Se crea una estructura con los nodos Include (1.2.2) o HashDataInfo (1.1.1) que contienen las URIs que apuntan a estas IDs
2093 			ArrayList<Element> nodosUriReferencia = new ArrayList<Element> (elementosIdSelloX.size());
2094 			Iterator<String> itIds = elementosIdSelloX.iterator();
2095 			while (itIds.hasNext()) {
2096 				String id = itIds.next();
2097 				Element uriNode = 
2098 					doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + nombreNodoUri);
2099 	        	Attr includeNodeUri = doc.createAttributeNS(null, tipoUri);
2100 	        	includeNodeUri.setValue(ConstantesXADES.ALMOHADILLA + id);
2101 	        	NamedNodeMap atributosNodo = uriNode.getAttributes();
2102 	        	atributosNodo.setNamedItem(includeNodeUri);
2103 	        	
2104 	        	nodosUriReferencia.add(uriNode);
2105 			}
2106 			
2107 	        // Se escribe en el nodo SigAndRefsTimeStamp el listado obtenido por orden
2108 			Iterator<Element> itUrisReferencia = nodosUriReferencia.iterator();
2109 			while (itUrisReferencia.hasNext()) {
2110 				Element includeNode = itUrisReferencia.next();			
2111 				sigAndRefsTimeStampElement.appendChild(includeNode);
2112 			}
2113 		}
2114 		
2115 		// Se obtiene el Array de bytes de los nodos obtenidos
2116 		byte[] byteData = null;
2117 		try {
2118 			byteData = UtilidadTratarNodo.obtenerByte(elementosSelloX, CanonicalizationEnum.C14N_OMIT_COMMENTS);
2119 		} catch (FirmaXMLError e) {
2120 			throw new Exception(e.getMessage(), e);
2121 		}
2122 		
2123 		// Calculamos el hash del sello de tiempo y lo escribimos en el nodo como String del array de bytes calculado
2124 		TSCliente tsCli = null;
2125 //        if(estadoProxy) {
2126 //			System.setProperty("http.proxyHost", servidorProxy);
2127 //			System.setProperty("http.proxyPort", Integer.toString(numeroPuertoProxy));
2128 //			if (isProxyAuth) {
2129 //				Authenticator.setDefault(new SimpleAuthenticator(proxyUser, proxyPass));
2130 //			} 
2131 //			else {
2132 //				Authenticator.setDefault(null);
2133 //			}
2134 //        } 
2135 		
2136 		TimeStamp timeStamp = TimeStamp.stampDocument(byteData, servidorTSA);
2137 		String hashSelloX = Util.encodeBase64(timeStamp.toDER());
2138 
2139 //        tsCli = new TSCliente(servidorTSA.toString(),algoritmoTSA);
2140 //        
2141 //        try {
2142 //			byteData = tsCli.generarSelloTiempo(byteData);
2143 //			Util.saveFile(new File ("c:/temp/ts.der"), byteData);
2144 //		} catch (TSClienteError e) {
2145 //			throw new Exception("Error generando sello de tiempos", e) ;
2146 //		}
2147 //		String hashSelloX = new String(Base64Coder.encode(byteData));
2148 		
2149 		// Se crea el nodo canonicalizationMethod en los esquemas 1.2.2 y 1.3.2
2150     	if (!ConstantesXADES.SCHEMA_XADES_111.equals(DEFAULT_XADES_SCHEMA_URI)) {
2151     		Element canonicalizationElemento = doc.createElementNS(ConstantesXADES.SCHEMA_DSIG, xmldsigNS + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.CANONICALIZATION_METHOD);		
2152     		Attr canonicalizationAttribute = doc.createAttributeNS(null, ConstantesXADES.ALGORITHM);
2153     		canonicalizationAttribute.setValue(Transforms.TRANSFORM_C14N_OMIT_COMMENTS);
2154     		canonicalizationElemento.getAttributes().setNamedItem(canonicalizationAttribute);
2155 
2156     		sigAndRefsTimeStampElement.appendChild(canonicalizationElemento);
2157     	}
2158 		
2159 		// Escribimos el resultado en el nodo EncapsulatedTimeStamp
2160 		Element encapsulatedTimeStampNode = 
2161 			doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.ENCAPSULATED_TIME_STAMP);
2162 		encapsulatedTimeStampNode.appendChild(doc.createTextNode(hashSelloX));	
2163 		sigAndRefsTimeStampElement.appendChild(encapsulatedTimeStampNode);
2164 
2165         return doc;
2166     }
2167     
2168     /**
2169      * Este metodo añade la implementación del sello de tiempo de tipo 2 (explícito) para 
2170      * XADES-X según los esquemas 1.1.1, 1.2.2 y 1.3.2.
2171      * Los elementos sobre los que se calcula el sello son los siguientes:
2172 	 * 		- CompleteCertificateRefs
2173 	 * 		- CompleteRevocationRefs
2174 	 * 	Opcionalmente en el esquema 1.2.2 y 1.3.2:
2175 	 * 		- AttributeCertificateRefs
2176 	 * 		- AttributeRevocationRefs
2177 	 * 
2178      * @param Element UnsignedSignatureProperties Nodo a partir del cual se añade el nodo RefsOnlyTimeStamp
2179      * @return Documento de firma con formato XADES-X
2180      * @throws Exception En caso de error
2181      */
2182     protected static Document addXadesX2(Element UnsignedSignatureProperties, String servidorTSA, 
2183     		String algoritmoTSA, String namespace) throws Exception {
2184     	// Se obtiene el formato de la constante URI en función del esquema
2185 		String tipoUri = null;
2186 		String nombreNodoUri = null;
2187 		if (ConstantesXADES.SCHEMA_XADES_111.equals(DEFAULT_XADES_SCHEMA_URI)){
2188 			nombreNodoUri = ConstantesXADES.HASH_DATA_INFO;
2189 			tipoUri = ConstantesXADES.URI_MINUS;
2190 		} else {
2191 			nombreNodoUri = ConstantesXADES.INCLUDE;
2192 			tipoUri = ConstantesXADES.URI_MAYUS;
2193 		}
2194     	
2195     	// Se obtiene el documento que contiene al nodo UnsignedSignatureProperties
2196     	Document doc = UnsignedSignatureProperties.getOwnerDocument();
2197     	
2198     	// Se obtiene el nodo Signature que contiene al nodo UnsignedSignatureProperties (es el 4º padre, según esquema XAdES)
2199     	Node padre = UnsignedSignatureProperties.getParentNode();
2200     	for (int i = 0; i < 3; ++i) {
2201     		if (padre != null)
2202     			padre = padre.getParentNode();
2203     		else
2204     			// No se encuentra el nodo Signature
2205     			throw new Exception("No se encuentra el nodo Signature");
2206     	}
2207     	
2208     	Element signatureElement = null;
2209     	if (padre != null && ConstantesXADES.SIGNATURE.equals(padre.getLocalName()))
2210     		signatureElement = (Element)padre;
2211     	else
2212     		// No se encuentra el nodo Signature
2213     		throw new Exception("No se encuentra el nodo Signature");
2214     	 
2215     	// Se crea el nodo RefsOnlyTimeStamp
2216         Element refsOnlyTimeStampElement =
2217         	doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.REFS_ONLY_TIME_STAMP);
2218         
2219         // Se escribe una Id única
2220     	Attr informacionElementoSigTimeStamp = doc.createAttributeNS(null, ConstantesXADES.ID);
2221     	String idSelloTiempo = UtilidadTratarNodo.newID(doc, ConstantesXADES.SELLO_TIEMPO);
2222     	informacionElementoSigTimeStamp.setValue(idSelloTiempo);
2223     	ArrayList<String> idNodoSelloTiempo = new ArrayList<String>();
2224     	idNodoSelloTiempo.add(idSelloTiempo);
2225     	refsOnlyTimeStampElement.getAttributes().setNamedItem(informacionElementoSigTimeStamp);
2226         
2227         // Se coloca el nodo creado al final del nodo UnsignedSignatureProperties
2228         UnsignedSignatureProperties.appendChild(refsOnlyTimeStampElement);
2229         
2230         // Se obtiene el listado de elementos de un sello de tiempo XAdES X de tipo 2
2231         ArrayList<Element> elementosSelloX = null;
2232         try {
2233 			elementosSelloX = UtilidadXadesX.obtenerListadoXADESX2exp(DEFAULT_XADES_SCHEMA_URI, signatureElement, refsOnlyTimeStampElement);
2234 		} catch (BadFormedSignatureException e) {
2235 			throw new Exception(e.getMessage(), e);
2236 		} catch (FirmaXMLError e) {
2237 			throw new Exception(e.getMessage(), e);
2238 		}
2239 		
2240 		// Se añaden nodos de referencia a los nodos obtenidos para el cálculo del sello (sólo para esquemas 1.2.2 y 1.1.1)
2241 		if (ConstantesXADES.SCHEMA_XADES_111.equals(DEFAULT_XADES_SCHEMA_URI) ||
2242 				ConstantesXADES.SCHEMA_XADES_122.equals(DEFAULT_XADES_SCHEMA_URI)) {
2243 			// Se obtienen las Ids de los nodos del sello de tiempo X
2244 			ArrayList<String> elementosIdSelloX = UtilidadTratarNodo.obtenerIDs(elementosSelloX);
2245 			
2246 			// Se crea una estructura con los nodos Include (1.2.2) o HashDataInfo (1.1.1) que contienen las URIs que apuntan a estas IDs
2247 			ArrayList<Element> nodosUriReferencia = new ArrayList<Element> (elementosIdSelloX.size());
2248 			Iterator<String> itIds = elementosIdSelloX.iterator();
2249 			while (itIds.hasNext()) {
2250 				String id = itIds.next();
2251 				Element uriNode = 
2252 					doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + nombreNodoUri);
2253 	        	Attr includeNodeUri = doc.createAttributeNS(null, tipoUri);
2254 	        	includeNodeUri.setValue(ConstantesXADES.ALMOHADILLA + id);
2255 	        	NamedNodeMap atributosNodo = uriNode.getAttributes();
2256 	        	atributosNodo.setNamedItem(includeNodeUri);
2257 	        	
2258 	        	nodosUriReferencia.add(uriNode);
2259 			}
2260 			
2261 	        // Se escribe en el nodo RefsOnlyTimeStamp el listado obtenido, por orden
2262 			Iterator<Element> itUrisReferencia = nodosUriReferencia.iterator();
2263 			while (itUrisReferencia.hasNext()) {
2264 				Element includeNode = itUrisReferencia.next();			
2265 				refsOnlyTimeStampElement.appendChild(includeNode);
2266 			}
2267 		}
2268 		
2269 		// Se obtiene el Array de bytes de los nodos obtenidos
2270 		byte[] byteData = null;
2271 		try {
2272 			byteData = UtilidadTratarNodo.obtenerByte(elementosSelloX, CanonicalizationEnum.C14N_OMIT_COMMENTS);
2273 		} catch (FirmaXMLError e) {
2274 			throw new Exception(e.getMessage(), e);
2275 		}
2276 		
2277 		// Calculamos el hash del sello de tiempo y lo escribimos en el nodo como String del array de bytes calculado
2278 		TSCliente tsCli = null;
2279 //        if(estadoProxy) {
2280 //			System.setProperty("http.proxyHost", servidorProxy);
2281 //			System.setProperty("http.proxyPort", Integer.toString(numeroPuertoProxy));
2282 //			if (isProxyAuth) {
2283 //				Authenticator.setDefault(new SimpleAuthenticator(proxyUser, proxyPass));
2284 //			} 
2285 //			else {
2286 //				Authenticator.setDefault(null);
2287 //			}
2288 //        } 
2289         tsCli = new TSCliente(servidorTSA,algoritmoTSA);
2290         
2291         try {
2292 			byteData = tsCli.generarSelloTiempo(byteData);
2293 		} catch (TSClienteError e) {
2294 			throw new Exception("No se puede generar el sello de tiempos", e) ;
2295 		}
2296 		String hashSelloX = new String(Base64Coder.encode(byteData));
2297 		
2298 		// Se crea el nodo canonicalizationMethod en los esquemas 1.2.2 y 1.3.2
2299     	if (!ConstantesXADES.SCHEMA_XADES_111.equals(DEFAULT_XADES_SCHEMA_URI)) {
2300     		Element canonicalizationElemento = doc.createElementNS(ConstantesXADES.SCHEMA_DSIG, xmldsigNS + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.CANONICALIZATION_METHOD);		
2301     		Attr canonicalizationAttribute = doc.createAttributeNS(null, ConstantesXADES.ALGORITHM);
2302     		canonicalizationAttribute.setValue(Transforms.TRANSFORM_C14N_OMIT_COMMENTS);
2303     		canonicalizationElemento.getAttributes().setNamedItem(canonicalizationAttribute);
2304 
2305     		refsOnlyTimeStampElement.appendChild(canonicalizationElemento);
2306     	}
2307 		
2308 		// Escribimos el resultado en el nodo EncapsulatedTimeStamp
2309 		Element encapsulatedTimeStampNode = 
2310 			doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.ENCAPSULATED_TIME_STAMP);
2311 		encapsulatedTimeStampNode.appendChild(doc.createTextNode(hashSelloX));	
2312 		refsOnlyTimeStampElement.appendChild(encapsulatedTimeStampNode);
2313 
2314         return doc;
2315     }
2316 
2317     /**
2318      * Este metodo añade la implementacion para XADES-XL
2319      * @param doc Documento de firma con formato XADES-X
2320      * @param valorCertificado
2321      * @param valorRevocacion
2322      * @return Documento de firma con formato XADES-XL
2323      * @throws Exception
2324      */
2325     protected static Document addXadesXL(Element firma, ArrayList<RespYCerts> respuestasFirma, 
2326     		ArrayList<RespYCerts> respuestasSello, XAdESSchemas schema, String namespace)
2327     	throws Exception {
2328     	
2329     	// Recogemos el nodo UnsignedSignatureProperties del cual dependen los nodos
2330     	// que hay que añadir para completar la firma XADES-XL
2331     	Document doc = firma.getOwnerDocument();
2332         Element elementoPrincipal = null ;
2333 
2334         NodeList nodosUnsignedSignatureProperties = firma.getElementsByTagNameNS(schema.getSchemaUri(), ConstantesXADES.UNSIGNED_SIGNATURE_PROPERTIES);
2335         if(nodosUnsignedSignatureProperties.getLength() != 0)
2336             elementoPrincipal = (Element)nodosUnsignedSignatureProperties.item(0);
2337         else
2338         	// No se encuentra el nodo UnsignedSignatureProperties
2339             throw new Exception("No se encuentra el nodo UnsignedSignatureProperties");
2340         	
2341         // Se añaden los certificados referenciados en el nodo CertificateValues
2342         if(respuestasFirma != null) {
2343         	//-- Juntamos las listas para añadir todos los certificados
2344         	if (respuestasSello != null) {
2345         		respuestasFirma.addAll(respuestasSello);
2346         	}
2347         	
2348         	EncapsulatedX509Certificate encapsulatedX509certificate = null;
2349         	ArrayList<EncapsulatedX509Certificate> certs = new ArrayList<EncapsulatedX509Certificate> (); 
2350         	List<X509Certificate> lCertificadosIncluidos = new ArrayList<X509Certificate>();
2351 	        for(RespYCerts resp : respuestasFirma) {
2352         		
2353         		//-- no repetirlos
2354         		if (lCertificadosIncluidos.contains(resp.getCertstatus().getCertificate())) {
2355         			continue;
2356         		}
2357         		lCertificadosIncluidos.add(resp.getCertstatus().getCertificate());
2358         		
2359         		encapsulatedX509certificate = new EncapsulatedX509Certificate(schema, resp.getIdCertificado());
2360 	        	try {
2361 					encapsulatedX509certificate.setX509Certificate(resp.getCertstatus().getCertificate());
2362 				} catch (CertificateException e) {
2363 					logger.info(e.getMessage(), e);
2364 					throw new Exception("No ha sido posible crear el elemento 'encapsulatedX509certificate' ");
2365 				}
2366 	        	certs.add(encapsulatedX509certificate);
2367 	        }
2368 
2369 	        CertificateValues certificateValues = new CertificateValues(schema, certs);
2370 	        Element certificateValuesElement = null;
2371 	        try {
2372 	        	certificateValuesElement = certificateValues.createElement(doc, namespace);
2373 			} catch (InvalidInfoNodeException e) {
2374 				logger.info(e.getMessage(), e);				
2375 				throw new Exception("No ha sido posible crear el elemento 'certificateValues'");
2376 			}  
2377 			
2378 			// Se escribe una Id única
2379 	    	Attr atributoCertVal = doc.createAttributeNS(null, ConstantesXADES.ID);
2380 	    	String idCertVal = UtilidadTratarNodo.newID(doc, ConstantesXADES.CERTIFICATE_VALUES);
2381 	    	atributoCertVal.setValue(idCertVal);
2382 	    	certificateValuesElement.getAttributes().setNamedItem(atributoCertVal);
2383 			
2384 			elementoPrincipal.appendChild(certificateValuesElement);
2385 			
2386             // Se añade la respuesta del servidor OCSP			
2387             Element valoresElementosRevocados =
2388                 doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.REVOCATION_VALUES);
2389 
2390             Element valorElementOCSP =
2391                 doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.OCSP_VALUES);
2392             
2393             CRLValues valorElementoCRL = new CRLValues(schema);
2394 
2395             lCertificadosIncluidos = new ArrayList<X509Certificate>();
2396 	        int nOcspResps = 0;
2397 	        int nCRLSResps = 0;
2398  	        for(int i=0;i<respuestasFirma.size();i++) {
2399         		RespYCerts resp = respuestasFirma.get(i);
2400         		
2401         		//-- no repetirlos
2402         		if (lCertificadosIncluidos.contains(resp.getCertstatus().getCertificate())) {
2403         			continue;
2404         		}
2405         		lCertificadosIncluidos.add(resp.getCertstatus().getCertificate());
2406         		
2407         		if (i < respuestasFirma.size()-1) {
2408             		ICertStatus respStatus = resp.getCertstatus();
2409 	        		if (respStatus instanceof IOCSPCertStatus) {
2410 	        			nOcspResps++;
2411 	        			IOCSPCertStatus respOCSP = (IOCSPCertStatus) respStatus;
2412 	    	            Element valorElementoEncapsuladoOCSP = doc.createElementNS(DEFAULT_XADES_SCHEMA_URI, namespace + ConstantesXADES.DOS_PUNTOS + ConstantesXADES.ENCAPSULATED_OCSP_VALUE);
2413 	    	            valorElementoEncapsuladoOCSP.appendChild(
2414 	    	                    doc.createTextNode(new String(Base64Coder.encode(respOCSP.getEncoded()))));
2415 	    	            valorElementoEncapsuladoOCSP.setAttributeNS(null, ConstantesXADES.ID, resp.getIdRespStatus());
2416 	    	            valorElementOCSP.appendChild(valorElementoEncapsuladoOCSP);
2417 	        		}
2418 	        		else if (respStatus instanceof IX509CRLCertStatus) {
2419 	        			nCRLSResps++;
2420 	        			IX509CRLCertStatus respCRL = (IX509CRLCertStatus) respStatus;
2421 	        			try {
2422 	        				valorElementoCRL.addCRL(respCRL.getX509CRL(), resp.getIdRespStatus());
2423 						} catch (InvalidInfoNodeException ex) {
2424 							throw new Exception("No se pudo generar nodo EncapsulatedCRLValue", ex);
2425 						}
2426 	        		}
2427         		}
2428 	        }
2429 
2430             if (nCRLSResps > 0) {
2431             	try {
2432 					Element el = valorElementoCRL.createElement(doc, namespace);
2433 					valoresElementosRevocados.appendChild(el);
2434 				} catch (InvalidInfoNodeException ex) {
2435 					throw new Exception("No se pudo generar nodo CRLValues", ex);
2436 				}
2437             }
2438 
2439             if (nOcspResps > 0)
2440             	valoresElementosRevocados.appendChild(valorElementOCSP);
2441             
2442 			// Se escribe una Id única
2443 	    	Attr atributoRevVal = doc.createAttributeNS(null, ConstantesXADES.ID);
2444 	    	String idRevVal = UtilidadTratarNodo.newID(doc, ConstantesXADES.REVOCATION_VALUES);
2445 	    	atributoRevVal.setValue(idRevVal);
2446 	    	valoresElementosRevocados.getAttributes().setNamedItem(atributoRevVal);
2447             
2448             elementoPrincipal.appendChild(valoresElementosRevocados);
2449         }
2450 
2451         return doc;
2452     }
2453 
2454     protected static ArrayList<RespYCerts> convertICertStatus2RespYCerts(List<ICertStatus> status) {
2455     	ArrayList<RespYCerts> resps = new ArrayList<RespYCerts>((status != null) ? status.size() : 0);
2456     	if (status != null) {
2457     		Iterator<ICertStatus> itStatus = status.iterator();
2458     		while (itStatus.hasNext()) {
2459     			RespYCerts resp = new RespYCerts();
2460     			resp.setCertstatus(itStatus.next());
2461     			resps.add(resp);
2462     		}
2463      	}
2464      	return resps;
2465     }
2466 
2467     /*
2468      * Método que a partir de un objeto de validación MITyC obtiene un objeto de validación
2469      * de Arangí. Recursivamente obtiene las contrafirmas. Tiene en cuenta la validez de certificados.
2470      */
2471 	private ValidationResult getValidationResult(ResultadoValidacion resultadoValidacion, boolean esContrafirma) {
2472 		logger.debug("[XAdESSignature.getValidationResult]::Resultado validación: " + resultadoValidacion.getLog());
2473 		
2474 		//-- Si no estamos tratando una contrafirma, pero lo es, devolvemos null
2475 		if (!esContrafirma && resultadoValidacion.getDatosFirma().getContraFirma() != null &&
2476 				!resultadoValidacion.getDatosFirma().getContraFirma().isEmpty()) {
2477 			return null;
2478 		}
2479 		
2480 		//-- Llamar al método implementado por cada una de las subclases para interpretar
2481 		//-- el resultado.
2482 		int codigoResultadoValidacion = tratarResultadoValidacion (resultadoValidacion);
2483 		
2484 		//-- Completar con la información de la firma
2485 		DatosFirma datosFirma = resultadoValidacion.getDatosFirma();
2486 		X509Certificate certificate = null;
2487 		if (datosFirma.getCadenaFirma() != null) {
2488 			certificate = (X509Certificate)datosFirma.getCadenaFirma().getCertificates().get(0);
2489 		}
2490 		TimeStamp ts = null;
2491 		if (datosFirma.getDatosSelloTiempo() != null && !datosFirma.getDatosSelloTiempo().isEmpty()) {
2492 			ts = new TimeStamp (datosFirma.getDatosSelloTiempo().get(0).getTst());
2493 		}
2494 		OCSPResponse[] ocspResponses = null;
2495 		if (datosFirma.getDatosOCSP() != null && !datosFirma.getDatosOCSP().isEmpty()) {
2496 			ocspResponses = new OCSPResponse [datosFirma.getDatosOCSP().size()];
2497 			for (int j = 0; j < ocspResponses.length; j++) {
2498 				try {
2499 					OCSPResp oscpResp = new OCSPResp(datosFirma.getDatosOCSP().get(j).getRespuestaOCSP().getEncoded());
2500 					ocspResponses[j] = new OCSPResponse(oscpResp);
2501 				} catch (MalformedOCSPResponseException e) {
2502 					logger.info("[XAdESSignature.getValidationResult]::Una de las respuestas OCSP está mal formada", e);
2503 				} catch (IOException e) {
2504 					logger.info("[XAdESSignature.getValidationResult]::Una de las respuestas OCSP está mal formada", e);
2505 				}
2506 			}
2507 		}
2508 		
2509 		ValidationResult result = new ValidationResult(codigoResultadoValidacion, certificate, ts==null?datosFirma.getFechaFirma():ts.getTime(), ts, ocspResponses);
2510 		
2511 		//-- Añadir contrafirmas si las hay (llamada recursiva a este método)
2512 		ArrayList<ResultadoValidacion> lContrafirmas = resultadoValidacion.getContrafirmadoPor();
2513 		if (lContrafirmas != null && !lContrafirmas.isEmpty()) {
2514 			ValidationResult[] arrayContrafirmas = new ValidationResult[lContrafirmas.size()];
2515 			int i = 0;
2516 			for (Iterator<ResultadoValidacion> iterator = lContrafirmas.iterator(); iterator.hasNext();) {
2517 				ResultadoValidacion resultadoValidacionContrafirma = iterator.next();
2518 				arrayContrafirmas[i] = getValidationResult (resultadoValidacionContrafirma, true);
2519 				i++;
2520 			}
2521 			result.setCounterSignatures(arrayContrafirmas);
2522 		}
2523 		
2524 		//-- Devolve resultado
2525 		return result;
2526 	}
2527 
2528     /*
2529      * Método que a partir de un objeto de validación MITyC obtiene un objeto de validación
2530      * de Arangí. No tiene en cuenta la validez de certificados.
2531      */
2532 	private ValidationResult getValidationResultSignatureOnly(ResultadoValidacion resultadoValidacion, boolean esContrafirma) {
2533 		logger.debug("[XAdESSignature.getValidationResultSignatureOnly]::Resultado validación: " + resultadoValidacion.getLog());
2534 		
2535 		//-- Si no estamos tratando una contrafirma, pero lo es, devolvemos null
2536 		if (!esContrafirma && resultadoValidacion.getDatosFirma().getContraFirma() != null &&
2537 				!resultadoValidacion.getDatosFirma().getContraFirma().isEmpty()) {
2538 			return null;
2539 		}
2540 		
2541 		//-- Llamar al método implementado por cada una de las subclases para interpretar
2542 		//-- el resultado.
2543 		int codigoResultadoValidacion = tratarResultadoValidacionSoloFirma (resultadoValidacion);
2544 		
2545 		//-- Completar con la información de la firma
2546 		DatosFirma datosFirma = resultadoValidacion.getDatosFirma();
2547 		X509Certificate certificate = (X509Certificate)datosFirma.getCadenaFirma().getCertificates().get(0);
2548 		TimeStamp ts = null;
2549 		if (datosFirma.getDatosSelloTiempo() != null && !datosFirma.getDatosSelloTiempo().isEmpty()) {
2550 			ts = new TimeStamp (datosFirma.getDatosSelloTiempo().get(0).getTst());
2551 		}
2552 		OCSPResponse[] ocspResponses = null;
2553 		if (datosFirma.getDatosOCSP() != null && !datosFirma.getDatosOCSP().isEmpty()) {
2554 			ocspResponses = new OCSPResponse [datosFirma.getDatosOCSP().size()];
2555 			for (int j = 0; j < ocspResponses.length; j++) {
2556 				try {
2557 					OCSPResp oscpResp = new OCSPResp(datosFirma.getDatosOCSP().get(j).getRespuestaOCSP().getEncoded());
2558 					ocspResponses[j] = new OCSPResponse(oscpResp);
2559 				} catch (MalformedOCSPResponseException e) {
2560 					logger.info("[XAdESSignature.getValidationResult]::Una de las respuestas OCSP está mal formada", e);
2561 				} catch (IOException e) {
2562 					logger.info("[XAdESSignature.getValidationResult]::Una de las respuestas OCSP está mal formada", e);
2563 				}
2564 			}
2565 		}
2566 		
2567 		ValidationResult result = new ValidationResult(codigoResultadoValidacion, certificate, ts==null?datosFirma.getFechaFirma():ts.getTime(), ts, ocspResponses);
2568 		
2569 		//-- Añadir contrafirmas si las hay (llamada recursiva a este método)
2570 		ArrayList<ResultadoValidacion> lContrafirmas = resultadoValidacion.getContrafirmadoPor();
2571 		if (lContrafirmas != null && !lContrafirmas.isEmpty()) {
2572 			ValidationResult[] arrayContrafirmas = new ValidationResult[lContrafirmas.size()];
2573 			int i = 0;
2574 			for (Iterator<ResultadoValidacion> iterator = lContrafirmas.iterator(); iterator.hasNext();) {
2575 				ResultadoValidacion resultadoValidacionContrafirma = iterator.next();
2576 				arrayContrafirmas[i] = getValidationResultSignatureOnly (resultadoValidacionContrafirma, true);
2577 				i++;
2578 			}
2579 			result.setCounterSignatures(arrayContrafirmas);
2580 		}
2581 		
2582 		//-- Devolver resultado
2583 		return result;
2584 	}
2585 
2586 	/*
2587 	 * Trata el resultado para comprobar sólo la firma (no los certificados)
2588 	 */
2589 	private int tratarResultadoValidacionSoloFirma(ResultadoValidacion resultadoValidacion) {
2590 		if (resultadoValidacion.getNivelValido() == null || resultadoValidacion.getNivelValido().equals("")) {
2591 			if (resultadoValidacion.getLog().toLowerCase().indexOf("firma inválida") > -1) {
2592 				//certificado válido, el problema será con la firma
2593 				logger.debug("[XAdESBESSignature.tratarResultadoValidacionSoloFirma]::La firma no es válida");
2594 				return ValidationResult.RESULT_SIGNATURE_NOT_MATCH_DATA;
2595 			} 
2596 		} 
2597 		
2598 		//válido
2599 		logger.debug("[XAdESSignature.tratarResultadoValidacionSoloFirma]::La firma ha pasado la validación");
2600 		return ValidationResult.RESULT_VALID;
2601 		
2602 	}
2603 	
2604 	/**
2605 	 * Obtener validador:
2606 	 * 
2607 	 * Si no se pasa documento:
2608 	 * <ul>
2609 	 * 	<li>Se busca una referencia a un fichero</li>
2610 	 * 	<li>Se busca una referencia a una URL</li>
2611 	 * 	<li>Comportamiento por defecto: se busca una referencia dentro del XML</li>
2612 	 * </ul>
2613 	 * 
2614 	 * Si se pasa el documento:
2615 	 * <ul>
2616 	 * 	<li>Si es un attached se mira si el documento corresponde con el attached (él, 
2617 	 * 		su base64 o su hash en base64 (SHA-1 o SHA-256). Si se corresponde se utiliza
2618 	 * 		el comportamiento por defecto.</li>
2619 	 * 	<li>Si es un detached se valida el documento</li>
2620 	 * </ul>
2621 	 * 
2622 	 * @param document
2623 	 * @return
2624 	 */
2625 	private ValidarFirmaXML loadValidator (IDocument document) {
2626 	    ValidarFirmaXML validator = new ValidarFirmaXML();
2627 	    if (document == null) {
2628 		    validator.addResolver(new FileResourceData());
2629 		    validator.addResolver(new URLResourceData());
2630 	    } else {
2631 	    	String attachedDocument = null;
2632 			try {
2633 				attachedDocument = getAttachedDocument();
2634 			} catch (Exception e1) {
2635 				logger.info("[XAdESSignature.loadValidator]::No se puede obtener el documento attached. En la validación se indicará que no existe");
2636 			} 
2637 	    	if (attachedDocument == null) {
2638 	    		//-- es detached
2639 	    		validator.addResolver(new UnknownFileResourceData(document));
2640 	    	} else {
2641 	    		//-- es attached
2642 	    		byte[] bAttachedDocument = Util.decodeBase64(attachedDocument);
2643 	    		boolean documentsMatch = true;
2644 	    		byte[] externalDocument;
2645 				try {
2646 					externalDocument = Util.readStream(document.getInputStream());
2647 					
2648 		    		if (!attachedDocument.equals (new String (externalDocument, getEncoding()))) {
2649 		    			// no son el mismo documento. comprobar base64
2650 		    			if (!Arrays.equals(bAttachedDocument, externalDocument)) {
2651 		    				// no es el documento en base64. comprobar sha-1
2652 	    					ByteArrayInputStream bais = new ByteArrayInputStream (externalDocument);
2653 	    					InputStreamDocument isd = new InputStreamDocument (bais);
2654 	    					byte[] hash = null;
2655 							try {
2656 								hash = isd.getHash(HashingAlgorithm.SHA1);
2657 							} catch (HashingException e) {
2658 				    			logger.debug("[XAdESSignature.loadValidator]::No se puede obtener hash SHA-1", e);
2659 							}
2660 		    				if (hash == null || (!Arrays.equals(bAttachedDocument, hash) && !attachedDocument.equals (Util.toHexadecimal(hash)))) {
2661 		    					// no es el sha-1. comprobar el sha-256
2662 		    					hash = null;
2663 		    					bais = new ByteArrayInputStream (externalDocument);
2664 		    					isd = new InputStreamDocument (bais);
2665 		    					try {
2666 									hash = isd.getHash(HashingAlgorithm.SHA256);
2667 								} catch (HashingException e) {
2668 					    			logger.debug("[XAdESSignature.loadValidator]::No se puede obtener hash SHA-256", e);
2669 								}
2670 		    					if (hash == null || (!Arrays.equals(bAttachedDocument, hash) && !attachedDocument.equals (Util.toHexadecimal(hash)))) {
2671 			    					documentsMatch = false;
2672 			    				}
2673 		    				}
2674 		    			}
2675 		    		}
2676 				} catch (IOException e) {
2677 	    			logger.debug("[XAdESSignature.loadValidator]::No se puede obtener el documento externo", e);
2678 				}
2679 	    		
2680 	    		//-- conclusión: si no coinciden los documentos añadimos un validador que siempre devolverá
2681 				//-- que las firmas no son válidas
2682 	    		if (!documentsMatch) {
2683 	    			validator.addResolver(new ToxicResourceData());
2684 	    		}
2685 	    	}
2686 	    }
2687 
2688 	    return validator;
2689 	}
2690 
2691 	/**
2692 	 * Obtiene un valor contenido dentro del tag DataObjectFormat de la firma. Si este valor
2693 	 * no se añadió se devolverá null.
2694 	 * 
2695 	 * @param tagName Nombre del tag
2696 	 * @return Valor
2697 	 */
2698 	private String getDataObjectFormatValue (String tagName) {
2699 		logger.debug("[XAdESSignature.getDataObjectFormatValue]::Entrada");
2700 		
2701 		//-- Obtener el nodo
2702 		XPathFactory factory = XPathFactory.newInstance();
2703 		XPath xpath = factory.newXPath();
2704 		try {
2705 			XPathExpression expr = xpath.compile("//*[local-name()='Object']/*[local-name()='QualifyingProperties']/*[local-name()='SignedProperties']/" +
2706 					"*[local-name()='SignedDataObjectProperties']/*[local-name()='DataObjectFormat']/*[local-name()='" + tagName + "']");
2707 			NodeList descriptionNodes = (NodeList) expr.evaluate (xadesDocument, XPathConstants.NODESET);
2708 			if (descriptionNodes == null || descriptionNodes.getLength() == 0) {
2709 				logger.debug("[XAdESSignature.getDataObjectFormatValue]::No existe la descripción del documento en la firma");
2710 				return null;
2711 			}
2712 			
2713 			return descriptionNodes.item(0).getTextContent();
2714 			
2715 		} catch (Exception e) {
2716 			logger.info ("[XAdESSignature.getDataObjectFormatValue]::Error inesperado", e);
2717 			return null;
2718 		}
2719 
2720 	}
2721 	
2722 	/*
2723 	 * Método de validación común tanto si se valida con CAList como con
2724 	 * servicios de validación
2725 	 */
2726 	private ValidationResult[] isValidCommon(IDocument document, CAList caList, List<CertificateValidationService> validationServices)
2727 			throws SignatureException {
2728 		
2729 		logger.debug("[XAdESSignature.isValid]::Entrada::" + Arrays.asList(new Object[] { document, caList, validationServices }));
2730 		
2731 		ExtraValidators extraValidator;
2732 		if (caList != null) {
2733 			extraValidator = new ExtraValidators(null, new CAListCertStatusRecover(caList, true), null);
2734 		} else {
2735 			extraValidator = new ExtraValidators(null, new ValidationServicesCertStatusRecover(validationServices), null);
2736 		}
2737 	    ValidarFirmaXML validator = loadValidator (document);
2738 	    List<ResultadoValidacion> results;
2739 		try {
2740 			results = validator.validar(this.xadesDocument, "./", extraValidator);
2741 		} catch (FirmaXMLError e) {
2742 			logger.info("[XAdESSignature.isValid]::No ha sido posible validar la firma", e);
2743 		    throw new SignatureException("No ha sido posible validar la firma", e);
2744 		}
2745 		
2746 	    ArrayList<ValidationResult> result = new ArrayList<ValidationResult>();
2747 	    for (Iterator<ResultadoValidacion> iterator = results.iterator(); iterator.hasNext();) {
2748 			ResultadoValidacion resultadoValidacion = iterator.next();
2749 			ValidationResult validationResult = getValidationResult (resultadoValidacion, false);
2750 			if (validationResult != null) {
2751 				result.add(validationResult);
2752 			}
2753 			
2754 		}
2755 		
2756 		return result.toArray(new ValidationResult[0]);
2757 	}
2758 
2759 	/**
2760 	 * Busca el nombre utilizado en el espacio de nombres del ETSI. Las 
2761 	 * clases del MITyC utilizan 'etsi' pero @Firma usa 'xades'.
2762 	 * 
2763 	 * @param element Elemento sobre el que se realiza la búsqueda
2764 	 * @return el nombre del espacio de nombres o el nombre por defecto
2765 	 */
2766     protected static String searchXAdESNamespace(Element element) {
2767     	
2768 		XPathFactory factory = XPathFactory.newInstance();
2769 		XPath xpath = factory.newXPath();
2770 		try {
2771 			XPathExpression expr = xpath.compile("//*[local-name()='SignedSignatureProperties']");
2772 			Node sspNode = (Node) expr.evaluate (element, XPathConstants.NODE);
2773 			if (sspNode != null && sspNode.getPrefix() != null) {
2774 				return sspNode.getPrefix();
2775 			}
2776 		} catch (Exception e) {
2777 		}
2778     	
2779 		return xadesNS;
2780 	}
2781 
2782     protected String nodeToString(Node node) {
2783     	StringWriter sw = new StringWriter();
2784     	try {
2785     		Transformer t = TransformerFactory.newInstance().newTransformer();
2786     		t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
2787     		t.setOutputProperty(OutputKeys.INDENT, "yes");
2788     		t.transform(new DOMSource(node), new StreamResult(sw));
2789     	} catch (TransformerException te) {
2790     		System.out.println("nodeToString Transformer Exception");
2791     	}
2792     	return sw.toString();
2793     }
2794 }