package es.uji.security.crypto.xmldsign.odf; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.security.Provider; import javax.xml.crypto.Data; import javax.xml.crypto.MarshalException; import javax.xml.crypto.OctetStreamData; import javax.xml.crypto.URIDereferencer; import javax.xml.crypto.URIReference; import javax.xml.crypto.URIReferenceException; import javax.xml.crypto.XMLCryptoContext; import javax.xml.crypto.dsig.Reference; import javax.xml.crypto.dsig.XMLSignature; import javax.xml.crypto.dsig.XMLSignatureException; import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.dom.DOMValidateContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jcp.xml.dsig.internal.dom.DOMSubTreeData; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.sun.org.apache.xpath.internal.XPathAPI; import es.uji.security.crypto.VerificationResult; public class ODFSignatureVerifier { public VerificationResult verify(InputStream data, Provider provider) throws IOException, ParserConfigurationException, SAXException, MarshalException, XMLSignatureException { // Acceso a los ficheros contenidos en el ODF final ODFDocument odt = new ODFDocument(data); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); DocumentBuilder db = dbf.newDocumentBuilder(); // Documento de firmas byte[] documentData = odt.getEntry("META-INF/documentsignatures.xml"); final Document d = db.parse(new ByteArrayInputStream(documentData)); // Recuperamos el nodo Signature NodeList nl = d.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); VerificationResult verificationResult = new VerificationResult(); // Establecemos el contexto de validacion for (int i = 0; i < nl.getLength(); i++) { DOMValidateContext valContext = new DOMValidateContext(new X509KeySelector(), nl.item(i)); valContext.setURIDereferencer(new URIDereferencer() { public Data dereference(URIReference uriReference, XMLCryptoContext context) throws URIReferenceException { Data result = null; // El elemento es una referencia interna dentro del documento if (uriReference.getURI().startsWith("#")) { Document document = d; Node node; try { node = XPathAPI.selectSingleNode(document.getDocumentElement(), "//*[@Id='" + uriReference.getURI().substring(1) + "']"); result = new DOMSubTreeData(node, true); } catch (TransformerException e) { throw new URIReferenceException(e.getMessage(), e); } } // El elemento es un fichero del ODF else { try { byte[] resourceData = odt.getEntry(uriReference.getURI()); result = new OctetStreamData(new ByteArrayInputStream(resourceData)); } catch (Exception e) { throw new URIReferenceException(e.getMessage(), e); } } return result; } }); // Validamos la firma XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); XMLSignature signature = fac.unmarshalXMLSignature(valContext); if (signature.validate(valContext)) { verificationResult.setValid(true); } else { verificationResult.setValid(false); boolean sv = signature.getSignatureValue().validate(valContext); if (sv == false) { for (Object o : signature.getSignedInfo().getReferences()) { Reference reference = (Reference) o; boolean refValid = reference.validate(valContext); verificationResult.addError(reference.getURI() + " - validity status: " + refValid); } } } } return verificationResult; } }