【问题标题】:How to generate an internally-detached XML signature in Java如何在 Java 中生成内部分离的 XML 签名
【发布时间】:2020-08-29 18:16:26
【问题描述】:

我不明白如何将签名节点作为数据节点的兄弟节点。我发现的示例来自 Oracle,但仅涵盖了正常的分离签名,其中 XML 作为 URI 传递给 Reference 对象。

参考 Oracle 示例:https://docs.oracle.com/javase/8/docs/technotes/guides/security/xmldsig/GenDetached.java

【问题讨论】:

    标签: java xml security pki xml-dsig


    【解决方案1】:

    一种方法如下:

    第 1 步 - 以字符串形式获取签名 XML。

    如下更改链接中的示例GenDetached 代码,使输出为字符串。

    在类的底部进行了以下更改:

    // output the resulting document
    OutputStream os = System.out;
    //if (args.length > 0) {
    //    os = new FileOutputStream(args[0]);
    //} else {
    //    os = System.out;
    //}
    
    // my changes, to write to a string:
    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer trans = tf.newTransformer();
    StringWriter writer = new StringWriter();
    trans.transform(new DOMSource(doc), new StreamResult(writer));
    return writer.toString();
    

    同时更改方法签名,使其返回一个字符串 - 例如:

    public class GenDetached {
        public static String generate() throws Exception {
            // code not shown
        }
    }
    

    第 2 步 - 将签名数据添加到您的目标 XML 文档中。

    假设我们有以下目标文档:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <root>
        <data>all your data in here...</data>
    </root>
    

    以下代码从签名 XML 中提取 &lt;Signature&gt; 节点并将其添加为文档中 &lt;root&gt; 节点的子节点:

    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.DocumentBuilder;
    import org.xml.sax.InputSource;
    import org.w3c.dom.Document;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    import java.io.StringReader;
    import javax.xml.transform.TransformerFactory;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.OutputKeys;
    import javax.xml.transform.dom.DOMSource;
    import javax.xml.transform.stream.StreamResult;
    import java.io.StringWriter;
    
    ...
    
    String signatureXml = GenDetached.generate();
    
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    // My test document to hold the data and the signature:
    String xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><root><data>foo</data></root>";
    
    Document doc = db.parse(new InputSource(new StringReader(xmlString)));
    Node docRootNode = doc.getFirstChild();
    
    Document sig = db.parse(new InputSource(new StringReader(signatureXml)));
    NodeList sigNodeList = sig.getElementsByTagName("Signature");
    Node sigNode = sigNodeList.item(0);
    
    // First import the signature node into the main document:
    Node docImportedNode = doc.importNode(sigNode, true);
    // Then add the signature node to the main document's root:
    docRootNode.appendChild(docImportedNode);
    
    // Show the output (as a String in this case, for the demo):
    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer trans = tf.newTransformer();
    trans.setOutputProperty(OutputKeys.INDENT, "yes");
    StringWriter writer = new StringWriter();
    trans.transform(new DOMSource(doc), new StreamResult(writer));
    System.out.println(writer.toString());
    

    结果是这样的(细节省略):

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <root>
        <data>foo</data>
        <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo>
                ...
            </SignedInfo>
            <SignatureValue>...</SignatureValue>
            <KeyInfo>
                <KeyValue>
                    <DSAKeyValue>
                        ...
                    </DSAKeyValue>
                </KeyValue>
            </KeyInfo>
        </Signature>
    </root>
    

    希望对您有所帮助。

    关于问题中的“内部分离”术语的小问题(Wikipedia 提供):

    用于在其包含的 XML 文档之外对资源进行签名的 XML 签名称为分离签名;如果它用于签署其包含文档的某些部分,则称为信封签名

    我假设这个例子是后者。

    【讨论】:

    • 谢谢,这正是我需要的。最后一个问题,如何引用目标文档,我想只提供本地文件的 URI 不是理想的选择?
    • documentation 第 4.4.3.1 节说“我们建议 XML 签名应用程序能够取消引用 HTTP 方案中的 URI。”而且,是的,使用本地文件 URI真的不适合。但是请查看同一链接中的示例 23 和 24。他们展示了如何在不使签名无效的情况下引用“文档的其余部分”。在这些情况下,URI 是一个空字符串(因为它们都在同一个文档中):&lt;Reference URI=""&gt;。我在现实生活中从未真正见过这样的文件(封装),如果这没有帮助,请道歉。
    猜你喜欢
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 2018-11-30
    • 2016-06-29
    • 2011-06-11
    • 1970-01-01
    • 2013-09-25
    • 1970-01-01
    相关资源
    最近更新 更多