package es.uji.security.crypto.xmldsign; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.xml.crypto.dsig.CanonicalizationMethod; import javax.xml.crypto.dsig.DigestMethod; import javax.xml.crypto.dsig.Reference; import javax.xml.crypto.dsig.SignatureMethod; import javax.xml.crypto.dsig.SignedInfo; import javax.xml.crypto.dsig.Transform; import javax.xml.crypto.dsig.XMLSignature; import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.dom.DOMSignContext; import javax.xml.crypto.dsig.keyinfo.KeyInfo; import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory; import javax.xml.crypto.dsig.keyinfo.X509Data; import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec; import javax.xml.crypto.dsig.spec.TransformParameterSpec; import javax.xml.crypto.dsig.spec.XPathFilterParameterSpec; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSSerializer; import com.sun.org.apache.xerces.internal.dom.DOMOutputImpl; import es.uji.security.crypto.ISignFormatProvider; import es.uji.security.crypto.SignatureOptions; import es.uji.security.crypto.SignatureResult; import es.uji.security.crypto.config.OS; public class XMLDsigSignatureFactory implements ISignFormatProvider { public SignatureResult formatSignature(SignatureOptions signatureOptions) throws Exception { byte[] toSign = OS.inputStreamToByteArray(signatureOptions.getDataToSign()); X509Certificate cer = signatureOptions.getCertificate(); PrivateKey pk = signatureOptions.getPrivateKey(); // We create DOM XMLSigantureFactory XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); // XPath filtering for multiple enveloped signatures support Transform transform = null; if (signatureOptions.isCoSignEnabled()) { transform = fac.newTransform(Transform.XPATH, new XPathFilterParameterSpec( "not(ancestor-or-self::dsig:Signature)", Collections.singletonMap("dsig", XMLSignature.XMLNS) )); } else { transform = fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null); } Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null), Collections.singletonList(transform), null, null); // Create the SignedInfo. SignedInfo si = fac .newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), fac.newSignatureMethod( SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref)); // Create the KeyInfo containing the X509Data. KeyInfoFactory kif = fac.getKeyInfoFactory(); List<Object> x509Content = new ArrayList<Object>(); x509Content.add(cer.getSubjectX500Principal().getName()); x509Content.add(cer); X509Data xd = kif.newX509Data(x509Content); KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd)); // Instantiate the document to be signed. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(toSign)); // Create a DOMSignContext and specify the RSA PrivateKey and // location of the resulting XMLSignature's parent element. DOMSignContext dsc = new DOMSignContext(pk, doc.getDocumentElement()); // Create the XMLSignature, but don't sign it yet. XMLSignature signature = fac.newXMLSignature(si, ki, null, "first", null); // Marshal, generate, and sign the enveloped signature. signature.sign(dsc); // Output the resulting document. ByteArrayOutputStream bos = new ByteArrayOutputStream(); // TransformerFactory tf = TransformerFactory.newInstance(); // Transformer trans = tf.newTransformer(); // trans.transform(new DOMSource(doc), new StreamResult(bos)); DOMImplementationLS domImplLS = (DOMImplementationLS) doc.getImplementation(); LSSerializer serializer = domImplLS.createLSSerializer(); serializer.getDomConfig().setParameter("namespaces", false); DOMOutputImpl output = new DOMOutputImpl(); output.setCharacterStream(new PrintWriter(bos)); serializer.write(doc, output); SignatureResult signatureResult = new SignatureResult(); signatureResult.setValid(true); signatureResult.setSignatureData(new ByteArrayInputStream(bos.toByteArray())); return signatureResult; } }