Java equivalent of C# XML signing method

∥☆過路亽.° 提交于 2019-12-30 02:34:15

问题


I have written the following .NET Framework 3.5 C# method which takes the location of an XML document and an object representation of an X509 digital certificate (with a private key) and returns the XML document as an object with the XML Signature (XMLDsig) embedded as first child element of the root.

The thing is that I direly need to be able to do the exact same procedure with Java SE 6, but I have not written any Java in ages and have no clue where to begin.

Can anyone provide the equivalent method in Java code that produces the exact same XML output?

private static XmlDocument SignXmlDocument(string xmlFilePath, X509Certificate2 certificate)
{
    // load xml from disk preserving whitespaces
    XmlDocument xmlDocument = new XmlDocument { PreserveWhitespace = true };
    xmlDocument.Load(xmlFilePath);

    // create signed xml with a same-document reference containing an enveloped-signature transform
    SignedXml signedXml = new SignedXml(xmlDocument) { SigningKey = certificate.PrivateKey };
    Reference reference = new Reference { Uri = "" };
    XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();            
    reference.AddTransform(env);
    signedXml.AddReference(reference);

    // embed public key information for signature validation purposes
    KeyInfo keyInfo = new KeyInfo();
    KeyInfoX509Data keyInfoX509Data = new KeyInfoX509Data(certificate, X509IncludeOption.ExcludeRoot);
    keyInfo.AddClause(keyInfoX509Data);
    signedXml.KeyInfo = keyInfo;

    // compute and retreive the signature xml
    signedXml.ComputeSignature();          
    XmlElement xmldsigXmlElement = signedXml.GetXml();

    // insert the signature xml into the xml document as first child of the root element
    xmlDocument.DocumentElement.PrependChild(xmlDocument.ImportNode(xmldsigXmlElement, true));

    return xmlDocument;
}

回答1:


The following does the same thing in Java. It requires a PKCS12 certificate file on disk.

import java.util.*;
import java.io.*;
import java.security.KeyStore;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.cert.X509Certificate;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;

public class XMLSigner {

    public static void signXmlDocumentOnDisk(String fileToBeSignedPath, String signedFileSavePath, String pkcs12CertificateFilePath, String password) throws Exception {
        XMLSignatureFactory fac = getXMLSignatureFactory();
        Reference ref = getSHA1WholeDocumentEnvelopedTransformReference(fac);
        SignedInfo si = getSignedInfo(fac, ref);
        PrivateKeyEntry keyEntry = loadPKCS12KeyStoreAndGetSigningKeyEntry(pkcs12CertificateFilePath, password);
        KeyInfo ki = getKeyInfoWithX509Data(keyEntry, fac);
        Document doc = instantiateDocumentToBeSigned(fileToBeSignedPath);
        signDocumentAndPlaceSignatureAsFirstChildElement(doc, keyEntry, fac, si, ki);
        writeResultingDocument(doc, signedFileSavePath);
    }

    private static XMLSignatureFactory getXMLSignatureFactory() {
        return XMLSignatureFactory.getInstance("DOM");
    }

    private static Reference getSHA1WholeDocumentEnvelopedTransformReference(XMLSignatureFactory fac) throws Exception {
        return 
            fac.newReference(
                "", 
                fac.newDigestMethod(DigestMethod.SHA1, null),
                Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)),
                null, 
                null
            );
    }

    private static SignedInfo getSignedInfo(XMLSignatureFactory fac, Reference ref) throws Exception {
        return 
            fac.newSignedInfo(
                fac.newCanonicalizationMethod(
                    CanonicalizationMethod.INCLUSIVE, 
                    (C14NMethodParameterSpec) null
                ),
                fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
                Collections.singletonList(ref)
            );
    }

    private static PrivateKeyEntry loadPKCS12KeyStoreAndGetSigningKeyEntry(String pkcs12CertificateFilePath, String password) throws Exception {
        KeyStore ks = KeyStore.getInstance("PKCS12");
        ks.load(new FileInputStream(pkcs12CertificateFilePath), password.toCharArray());    
        return (PrivateKeyEntry)ks.getEntry(ks.aliases().nextElement(), new KeyStore.PasswordProtection(password.toCharArray()));           
    }

    private static KeyInfo getKeyInfoWithX509Data(PrivateKeyEntry keyEntry, XMLSignatureFactory fac) {
        X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        List x509Content = new ArrayList();
        x509Content.add(cert.getSubjectX500Principal().getName());
        x509Content.add(cert);
        X509Data xd = kif.newX509Data(x509Content);
        return kif.newKeyInfo(Collections.singletonList(xd));
    }

    private static Document instantiateDocumentToBeSigned(String fileToBeSignedPath) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        return dbf.newDocumentBuilder().parse(new FileInputStream(fileToBeSignedPath));
    }

    private static void signDocumentAndPlaceSignatureAsFirstChildElement(Document doc, PrivateKeyEntry keyEntry, XMLSignatureFactory fac, SignedInfo si, KeyInfo ki) throws Exception {
        DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc.getDocumentElement(), doc.getDocumentElement().getFirstChild());
        XMLSignature signature = fac.newXMLSignature(si, ki);
        signature.sign(dsc);
    }

    private static void writeResultingDocument(Document doc, String signedFileSavePath) throws Exception {
        OutputStream os = new FileOutputStream(signedFileSavePath);
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
    }
}



回答2:


Check out the Java XML Digital Signature API: https://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html



来源:https://stackoverflow.com/questions/5330049/java-equivalent-of-c-sharp-xml-signing-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!