3

in a SOAP webservice I'm trying to consume there's the necessity of sending a XML with a structure that resembles this:

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

In which <Signature> has the contents:

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

How can I do it?

I'm trying with xmlsec1 --id-attr:Id Father --id-attr:Id Child, passing to it the file with Signature fields blank, but it only fills the first of them.

I also tried signing the child alone, putting it inside the father template and them trying to sign the father, but xmlsec1 ignores the second element (and changes the value of the first signature -- wasn't it supposed to be encapsulated inside its element?).


Probably unrelated, but who knows?

I would rather do this from inside Python code, but the three libraries I tried to use, python-xmlsec, pyxmlsec and xmldsig were all uncapable of generating/reconizing the URI attr of <Reference>. Probably because they lack the --id-attr of xmlsec1, but these problems I'm getting reveal the fact that I don't really understand this XML-signing stuff and, because of that, I'm doing stuff wrong and messing it all up. Please help me understand it.


EDIT

I've seem a lot of people with difficulties in these XML signing subject, but none of them were trying to sign two different elements in the same XML file. This case is not listed also at the w3C Scenarios FAQ, which makes everything look strange, because my webservice requires me that multiple signatures. Or don't? Here's the Schema they publish: https://github.com/proge/PyNFSe/blob/master/pysped_nfse/nfse.xsd#L539 (see this element <xsd:element name="EnviarLoteRpsEnvio"> and childs).

fiatjaf
  • 11,479
  • 5
  • 56
  • 72
  • So, in the signature element , what are you signing here? Also, what is xml-sec command here? – Zeus Dec 09 '13 at 21:29

1 Answers1

1

I think there is no method to do that with 3rd party libraries, most of applications needs only a signature for all XML content, not for particular elements.

Maybe, this helps you:

According to XSD relative to the "RecepcionarLoteRps" method

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

you need to sign every "Rps" on "ListaRps" inside "LoteRps" and finally sign the "LoteRps" element.

You can do that when you generate the XML step by step, generating the "ListaRps" element with all "Rps" and after get all "InfRps" elements and sign all of them or you can sign the "InfRps" immediately after created and add to the "ListaRps", finally you should sign "LoteRps".

Maybe you can do that too generating the full XML and after parse it getting the elements and sign it one by one with the appropiate order.

You have to code anyway to sign the XML as you need.

Take a look at assembla nfseWsClient, is developed with Java and JAX-WS but is a good initial point.

This two Classes will be insteresting for you

vzamanillo
  • 9,905
  • 1
  • 36
  • 56
  • How does `assinarLote` (I read it, but couldn't understand it all) know which element it has to sign? I tried to built the message manually like you said (`you need to sign every "Rps" on "ListaRps" inside "LoteRps" and finally sign the "LoteRps" element.`), but when I try to sign the "LoteRps" `xmlsec1` (and also three different Python bindings for `libxmlsec`) **signs again the "Rps"**, because that's the first element it founds (maybe?). – fiatjaf Dec 10 '13 at 14:24
  • I thought the problem was to get `xmlsec` to recognize the `Id` of the element which should be signed and add an `URI` to the `Reference` element at the `Signature`, but I couldn't solve it (_Assembla_ does it with in a strange way). Is this it? – fiatjaf Dec 10 '13 at 14:28
  • Here's the crucial part of the failed code I've written to build a "Rps" manually (with `Jinja2` templates), sign it, insert it into the global message template and then sign it: http://pastie.org/8542142 Please take a look at it. – fiatjaf Dec 10 '13 at 14:30
  • Look at lines from 451 to 462 in RecepcionarLoteRpsBusiness, the element "LoteRps" have an "id" attribute whos identify an unique "LoteRps" formed by an String literal + BigInteger with the lote number extracted from a database, at line 469 the code calls to ProcessSign.assinarLote(String xml, KeyStore ks, String alias, String senha, String id, String nomeCertificado) the id parameter is the same literal + BigInteger who identifies the "LoteRps" and is used to create a Reference object for SignedInfo. It's true, first signs all Rps, finally the full LoteRps XML with signed Rps is signed again. – vzamanillo Dec 10 '13 at 14:46
  • Assembla client uses a Reference Uri with the LoteRps Id to identify the element to sign, Reference ref = fac.newReference("#" + id, fac.newDigestMethod(DigestMethod.SHA1, null), transformList, null, null); and uses the InfRps attribute id to create a Reference Uri for Rps in "assinarRps". – vzamanillo Dec 10 '13 at 14:56