1

人们,

我已经阅读了此处的帖子和使用 JAXB 时处理数字签名的示例代码,并且遇到了一个问题,我认为这是通过 JAXB 编组将名称空间引入“SignedInfo”元素的问题。

我已经定义了一个 XSD,它将被以不同编程语言实现的多个应用程序使用。我将 XSD 编译为 JAXB 注释类以供我的实现使用(Jersey JAX-RS 和 JAX-WS)。我目前的流程如下:

  1. JAXB 对象是使用适当的数据创建的或从远程应用程序交付的。
  2. Blaise Doughan所述,将 JAXB 分配到 DOM 以进行签名。
  3. 使用创建封装签名的私钥签署 DOM。
  4. 将 DOM 解组到 JAXB 以用于 JAX-RS/WS 消息传递。

我被迫在我的 XSD 定义中的父元素末尾添加一个“xsd:any”元素,以便 DOM 到 JAXB 解组工作,否则嵌入的“签名”元素被删除。我还让 JAXBContext 知道 xmldsig 命名空间。

以下步骤顺序有效:JAXB -> DOM -> 签名 -> 验证

所以我知道签名工作正常。但是,以下序列验证失败:JAXB -> DOM -> 签名 -> JAXB -> DOM ->Validate

经过一些测试和阅读后,我的猜测是 JABX Marshaller 对“SignedInfo”的修改导致了问题,因为它为所有 xmlsig 元素添加了命名空间前缀。

这是 DOM 生成的 XML(缩写):

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
        <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
        <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/2001/04/xmlenc#sha512"/>
            <DigestValue>...</DigestValue>
        </Reference>
    </SignedInfo>
    <SignatureValue>...</SignatureValue>
    <KeyInfo>
        <X509Data>
            <X509SubjectName>...</X509SubjectName>
            <X509Certificate>...</X509Certificate>
        </X509Data>
    </KeyInfo>
</Signature>

这是从 JAXB 编组后的元素(ns2 在父元素中定义):

<ns2:Signature>
    <ns2:SignedInfo>
        <ns2:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
        <ns2:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
        <ns2:Reference URI="">
            <ns2:Transforms>
                <ns2:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
            </ns2:Transforms>
            <ns2:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha512"/>
            <ns2:DigestValue>...</ns2:DigestValue>
        </ns2:Reference>
    </ns2:SignedInfo>
    <ns2:SignatureValue>...</ns2:SignatureValue>
    <ns2:KeyInfo>
        <ns2:X509Data>
            <ns2:X509SubjectName>...</ns2:X509SubjectName>
            <ns2:X509Certificate>...</ns2:X509Certificate>
        </ns2:X509Data>
    </ns2:KeyInfo>
</ns2:Signature>

我的假设是否正确,这是验证失败的原因?

有没有办法在使用 JAXB 时保持“签名”元素不变?

是否有一个 CanonicalizationMethod 会忽略计算中的任何命名空间前缀?

此外,如果要更改已签名 XML 中的命名空间前缀,这是否也会导致验证失败(例如,从 ns1 更改为 abc)?我想知道如果其他应用程序序列化/反序列化 XML 并可能更改命名空间前缀,数字签名是否会失效?

感谢您的任何帮助!

约翰

4

2 回答 2

0

我今天花了很多时间试图找到一种方法来定制 JAXB 来解决这个问题。

从技术上讲,由 JAXB 生成的 XML 是正确的,但是有些服务器希望名称空间与其元素在一起,并且没有前缀(在我们的例子中是签名)。

我找到的唯一解决方案是手动替换命名空间前缀:

xml = xml.replace(" xmlns:ns2=\"http://www.w3.org/2000/09/xmldsig#\"", "");
xml = xml.replace("<ns2:Signature>",
        "<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\">");
xml = xml.replace("ns2:", "");

<nfeProc versao="3.10" xmlns="http://www.portalfiscal.inf.br/nfe" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#">
...
<ns2:Signature>
<ns2:SignedInfo>
<ns2:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>

后:

<nfeProc versao="3.10" xmlns="http://www.portalfiscal.inf.br/nfe">
...
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
于 2016-02-24T22:11:42.313 回答
0

我最终作弊了,我没有直接在我的 XML 中包含 Signature 元素,而是 gzip'ed 然后对 Signature 进行 mime 编码并将其包含在一个字符串元素中。我也对我正在签名的文档做了同样的事情,因为它也发生了命名空间操作。这产生了一个外部 XML 文档,其中包含有关所包含的内部(mime 编码)XML 文档和(mime 编码)数字签名的命名和元数据。我在 mime 编码之前使用了内部文档的 DOM 序列化和 Signature 来保留命名空间,然后让 JAXB 处理包含 mime 内容的外部文档的序列化。像魅力一样工作,在 mime 之前使用 gzip 真的减少了我的文档大小。唯一的缺点是在解码之前您不能再查看内部 XML 文档。

于 2016-04-05T15:37:12.767 回答