java - 如何在使用 javax.xml.crypto.dsig.* 签署 XML 文件时添加命名空间?

标签 java namespaces xmlsec

我正在尝试使用封装签名和 javax.xml.crypto.dsig.* 类对 xml 文件进行签名。结果,我得到了具有正确签名内容但未定义命名空间的文件。如何添加 xmlns:ds="http://www.w3.org/2000/09/xmldsig#"命名空间和相应的 ds 前缀? 我看不到任何可以定义它的地方。

示例代码:

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

    (...)

    XMLSignature signature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo);

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

给出示例 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>

但我想要:

<?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>

最佳答案

以下是来自 Oracle 的用于生成封装签名的示例代码。我猜你要找的是 dsc.setDefaultNamespacePrefix("dsig");如下例所示。

    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));

关于java - 如何在使用 javax.xml.crypto.dsig.* 签署 XML 文件时添加命名空间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16300486/

相关文章:

java - 在 Eclipse 中运行 junit 测试时出现 ClassNotFoundException

java - Android 从类路径加载文件导致崩溃

python - 系统错误 : null argument to internal routine in xmlsec

python - 获取: "ERROR: Failed building wheel for xmlsec" when using docker to containerize flask app

c++ - 在 libxml2 和 xmlsec 中禁用调试输出

java - finally block 中的代码和 finally block 之后的代码有什么区别?

java - Hangman 代码问题 (Java)

c++ - 包含命名空间的类模板的前向声明导致编译错误

php - 子类可以从 PHP 中的父类继承命名空间别名吗?

python - 如何在 "correctly"复制一个 types.SimpleNamespace 对象?