How to add namespace while signing XML file using javax.xml.crypto.dsig.*?

java, namespaces, xmlsec

Solution

Below is the sample code from Oracle for generating enveloped signature. And i guess what you are looking for is dsc.setDefaultNamespacePrefix("dsig"); as shown in the example below.

    XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

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

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

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

    // Create a KeyValue containing the DSA PublicKey that was generated
    KeyInfoFactory kif = fac.getKeyInfoFactory();
    KeyValue kv = kif.newKeyValue(kp.getPublic());

    // Create a KeyInfo and add the KeyValue to it
    KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

    // Instantiate the document to be signed
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);
    Document doc =  dbf.newDocumentBuilder().parse(new FileInputStream(sourceFile));

    // Create a DOMSignContext and specify the DSA PrivateKey and
    // location of the resulting XMLSignature's parent element
    DOMSignContext dsc = new DOMSignContext(kp.getPrivate(), doc.getDocumentElement());
    dsc.setDefaultNamespacePrefix("dsig");

    // Create the XMLSignature (but don't sign it yet)
    XMLSignature signature = fac.newXMLSignature(si, ki);

    // Marshal, generate (and sign) the enveloped signature
    signature.sign(dsc);

    // output the resulting document
    OutputStream os;
    os = new FileOutputStream(DestinationFile);

    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer trans = tf.newTransformer();
    trans.transform(new DOMSource(doc), new StreamResult(os));

Problem

I'm trying to sign an xml file using enveloped signature and javax.xml.crypto.dsig.* classes. As a result I get file with correct Signature content but with no namespace defined. How can I add xmlns:ds="http://www.w3.org/2000/09/xmldsig#" namespace and corresponding ds prefixes? I don't see any place where I could define it. Example code: ``` XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM"); (...) XMLSignature signature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo); // Marshal, generate, and sign the enveloped signature. signature.sign(domSignContext); ``` gives example XML: ``` <?xml version="1.0" encoding="UTF-8"?> <test xmlns="http://different.namespace.com"> <someBody/> <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> <SignedInfo> <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <Reference URI=""> <Transforms> <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> </Transforms> <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <DigestValue>base64_digest</DigestValue> </Reference> </SignedInfo> <SignatureValue>some_base64</SignatureValue> <KeyInfo> <X509Data> <X509SubjectName>subject_data</X509SubjectName> <X509Certificate>some_more_base64</X509Certificate> </X509Data> <KeyValue> <RSAKeyValue> <Modulus>another_base64</Modulus> <Exponent>base64_as_well</Exponent> </RSAKeyValue> </KeyValue> </KeyInfo> </Signature> </test> ``` but I want: ``` <?xml version="1.0" encoding="UTF-8"?> <test xmlns="http://different.namespace.com" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <someBody/> <ds:Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <ds:Reference URI=""> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ds:DigestValue>base64_digest</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>some_base64</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509SubjectName>subject_data</ds:X509SubjectName> <ds:X509Certificate>some_more_base64</ds:X509Certificate> </ds:X509Data> <ds:KeyValue> <ds:RSAKeyValue> <ds:Modulus>another_base64</ds:Modulus> <ds:Exponent>base64_as_well</ds:Exponent> </ds:RSAKeyValue> </ds:KeyValue> </ds:KeyInfo> </ds:Signature> </test> ```

Original source