如何签署各种XML元素并签署其父元素?

时间:2013-11-28 21:48:50

标签: xml xml-signature xml-dsig

在我正在尝试使用的SOAP Web服务中,需要发送一个类似于此结构的XML:

<?xml version="1.0"?>
<TheData>
  <Father Id="zzz">
      <SomeInfo>1</SomeInfo>
      <List>
        <ElementOfList>
          <Child Id="foo">foo</Child>
          <Signature>
            ...
          </Signature>
        </ElementOfList>
        <ElementOfList>
          <Child Id="bar">bar</Child>
          <Signature>
            ...
          </Signature>
        </ElementOfList>
      </List>
  </Father>
  <Signature>
    ...
  </Signature>
</TheData>

其中<Signature>包含以下内容:

<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="#[the _Id_ attr of this Signature's sibling element]">
      <Transforms>
        <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
      </Transforms>
      <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
      <DigestValue>uCMzpgMnLCP9iESFQVgpmtQ5TRE=</DigestValue>
    </Reference>
  </SignedInfo>
  <SignatureValue>...</SignatureValue>
  <KeyInfo>
    <X509Data>
      <X509Certificate>...</X509Certificate>
    </X509Data>
  </KeyInfo>
</Signature>

我该怎么做?

我正在尝试xmlsec1 --id-attr:Id Father --id-attr:Id Child,将Signature字段空白的文件传递给它,但它只会填充第一个字段。

我也试过单独签名孩子,把它放在父模板中并试图签下父亲,但xmlsec1忽略了第二个元素(并改变了第一个签名的值 - 不是吗应该封装在其元素中?)。


可能不相关,但谁知道?

我宁愿在Python代码中执行此操作,但我尝试使用的三个库python-xmlsecpyxmlsecxmldsig都无法生成/重新构建{{1 } {at} URI。可能是因为他们缺少<Reference>的{​​{1}},但是我得到的这些问题表明我并不真正理解这种XML签名的东西,因此,我正在做的事情错了,搞砸了。请帮我理解。


修改

我似乎有很多人在这些XML签名主题中遇到困难,但他们都没有试图在同一个XML文件中签署两个不同的元素。这个案例也没有列在w3C Scenarios FAQ,这使得一切看起来都很奇怪,因为我的网络服务要求我有多个签名。或者不是吗?以下是他们发布的架构:https://github.com/proge/PyNFSe/blob/master/pysped_nfse/nfse.xsd#L539(请参阅此元素--id-attr和孩子们)。

1 个答案:

答案 0 :(得分:1)

我认为没有方法可以使用第三方库,大多数应用程序只需要所有XML内容的签名,而不是特定元素。

也许,这会对你有所帮助:

根据XSD相对于“RecepcionarLoteRps”方法

<s:element name="RecepcionarLoteRps">
    <s:complexType>
        <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="EnviarLoteRpsEnvio" type="tns:EnviarLoteRpsEnvio"/>
        </s:sequence>
    </s:complexType>
</s:element>
<s:complexType name="EnviarLoteRpsEnvio">
    <s:sequence>
        <s:element minOccurs="0" maxOccurs="1" name="LoteRps" type="tns:tcLoteRps"/>
        <s:element minOccurs="0" maxOccurs="1" name="Signature" type="s1:SignatureType"/>
    </s:sequence>
</s:complexType>
<s:complexType name="tcLoteRps">
    <s:sequence>
        <s:element minOccurs="1" maxOccurs="1" name="NumeroLote" type="s:unsignedLong"/>
        <s:element minOccurs="0" maxOccurs="1" name="Cnpj" type="s:string"/>
        <s:element minOccurs="0" maxOccurs="1" name="InscricaoMunicipal" type="s:string"/>
        <s:element minOccurs="1" maxOccurs="1" name="QuantidadeRps" type="s:int"/>
        <s:element minOccurs="0" maxOccurs="1" name="ListaRps" type="tns:ArrayOfRps"/>
    </s:sequence>
</s:complexType>
<s:complexType name="ArrayOfRps">
    <s:sequence>
        <s:element minOccurs="0" maxOccurs="unbounded" name="Rps" nillable="true" type="tns:Rps"/>
    </s:sequence>
</s:complexType>
<s:complexType name="Rps">
    <s:complexContent mixed="false">
        <s:extension base="tns:tcRps"/>
    </s:complexContent>
</s:complexType>
<s:complexType name="tcRps">
    <s:sequence>
        <s:element minOccurs="0" maxOccurs="1" name="InfRps" type="tns:tcInfRps"/>
        <s:element minOccurs="0" maxOccurs="1" name="Signature" type="s1:SignatureType"/>
    </s:sequence>
</s:complexType>

您需要在“LoteRps”内的“ListaRps”上签署每个“Rps”,最后签署“LoteRps”元素。

当您逐步生成XML时,可以生成带有所有“Rps”的“ListaRps”元素,并在获取所有“InfRps”元素并对其进行全部签名后,或者您可以立即签署“InfRps”后执行此操作创建并添加到“ListaRps”,最后你应该签署“LoteRps”。

也许你也可以这样做生成完整的XML并在解析之后获取元素并使用适当的顺序逐个签名。

无论如何,您必须编码以根据需要对XML进行签名。

看一下使用Java和JAX-WS开发的assembla nfseWsClient,但这是一个很好的初始点。

这两个课程对你来说很有意义