Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB Marshalling with xmldsig Signature

Is it possible to create jaxb marshaller which automatically adds digital signature to xml content.

For example if I have a class which is defined:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Test {
    @XmlElement
    private String info;

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }
}

And my xml which is produced by marshaller looks like:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><test><info>value</info></test>

And I expect it to look like:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <Security>
        <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo>
                <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
                <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                <Reference URI="">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#envelopedsignature"/>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue>4432kZ6c2JPwP3A=</DigestValue>
                </Reference>
            </SignedInfo>
            <SignatureValue>Mvbd4603knhh2LZTyE1MIiEF7N46b7GoTzxsqs5eyIXYNG96MFPIMo+P6okzIPzRKrL2obpf3V4D/F0gw5vM/UJwb2MvrCo/5JM5qvV0f09dzWLrgkPyShiQnFL2vzECwmMOrCA=</SignatureValue>
            <KeyInfo>
                <X509Data>
                        <X509Certificate>MIIEnjCCBAegAwIBAgIDJQDMA0GCSqGSICBMGSETU0VOMRgwFgYDVQQHEw82NTAwOCBXaWVzYmFkZW4xGjAYBgNVBkESE9MRElORyBBRzEiMCAGA1UEAxMZSW50ZXJuZXQgQmVudXR6ZXIgU2VydmljZTEqMCgGCSqGSIb3DQEJARbeVydmaWthdEBzY2h1ZmEtb25saW5lLmRlMB4XDTA5MDcyNzEwNTkyNVoXDTEwMDcyNzEwNTkyNVowgZsxCzAJdNVBATAkFMQLmRlMCYGfUdEgQfMB2BG3plcnRpZmlrYXRAc2NodWZhLW9ubGluZS5kZTAfsgkqhkiG9w0BAQQFAAOBgQB7DBly8bqksxrkwcmN2A/xfu3lm0IfGD6PoJ7JFgPq4aHBDWgdUW3EzvRE+cuFGjkoBvATKfcbF7ReTz+4C+dLJShYiN/HxUnxgiO7R2y4c/I4pNnmlfQT261/dNlQ8Wm8pyUeMcr32fxvtoY4dqlQy7GePmrHpR3HE/dMRAd6gA==</X509Certificate>
                </X509Data>
                <KeyValue>
                    <RSAKeyValue>
                        <Modulus>1EN/UxtM2fLYxxDmSxgjSd10AzCxvZtNGAER9j3+OMqZjBXG9uLiZR+GbtOXbsDz3fyiwEfu/FDeeGGESppYAL5foQ72t2ztV5w2GLtTH0K+wrlImmvoTdl6bsdC7RXAsXVxtlkoG0xL7HGwZLvM=</Modulus>
                        <Exponent>AQAB</Exponent>
                    </RSAKeyValue>
                </KeyValue>
            </KeyInfo>
        </Signature>
    </Security>
<test><info>value</info></test>

I hope there is a way to do it by marshaller? If not maybe there is any other simple way to sign an xml ?

Thanks in advance

like image 883
wojtek Avatar asked Jun 19 '13 14:06

wojtek


1 Answers

You will need to use JAXB to marshal your domain model to a DOM Document and then apply the signature to that using an approach like the following:

import java.security.*;
import java.util.Collections;
import javax.xml.bind.*;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Test.class);

        Test test = new Test();
        test.setInfo("value");

        Marshaller marshaller = jc.createMarshaller();
        DOMResult domResult = new DOMResult();
        marshaller.marshal(test, domResult);

        String providerName = System.getProperty("jsr105Provider",
                "org.jcp.xml.dsig.internal.dom.XMLDSigRI");

        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM",
                (Provider) Class.forName(providerName).newInstance());

        Reference ref = fac.newReference("", fac.newDigestMethod(
                DigestMethod.SHA1, null), Collections.singletonList(fac
                .newTransform(Transform.ENVELOPED, (XMLStructure) null)), null,
                null);

        SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(
                CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, (XMLStructure) null), fac
                .newSignatureMethod(SignatureMethod.DSA_SHA1, null),
                Collections.singletonList(ref));

        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(512);
        KeyPair kp = kpg.generateKeyPair();

        KeyInfoFactory kif = fac.getKeyInfoFactory();
        KeyValue kv = kif.newKeyValue(kp.getPublic());

        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

        Document doc = (Document) domResult.getNode();

        DOMSignContext dsc = new DOMSignContext(kp.getPrivate(),
                doc.getDocumentElement());

        XMLSignature signature = fac.newXMLSignature(si, ki);
        signature.sign(dsc);

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer t = tf.newTransformer();
        DOMSource source = new DOMSource(domResult.getNode());
        StreamResult result = new StreamResult(System.out);
        t.transform(source, result);
    }

}
like image 106
bdoughan Avatar answered Sep 20 '22 16:09

bdoughan