robrichards / xmlseclibs

A PHP library for XML Security
BSD 3-Clause "New" or "Revised" License
387 stars 181 forks source link

Add Reference Id #185

Open elvispdosreis opened 5 years ago

elvispdosreis commented 5 years ago

I have an xml document that I need to add multiple signatures in them, and I need to add the references, <ds:Reference URI=""> to <ds:Reference URI="#NFSe201800000113740">

<?xml version="1.0" encoding="utf-8"?>
<ListaNfse>
  <CompNfse xmlns="http://www.abrasf.org.br/nfse.xsd">
    <Nfse versao="2.03">
      <InfNfse Id="NFSe201800000113740">
          ...
          ...
          ...
      </InfNfse>
    </Nfse>
  </CompNfse>
</ListaNfse>
public function signXml($xml, $signRoot = true, $tags = ['InfNfse'])
    {
        // Load the XML to be signed
        $doc = new \DOMDocument();
        $doc->loadXML($xml);
        // Create a new Security object
        $objDSig = new XMLSecurityDSig();
        // Use the c14n exclusive canonicalization
        $objDSig->setCanonicalMethod(XMLSecurityDSig::C14N);
        // Sign using SHA-256
        $objDSig->addReference(
            $doc,
            XMLSecurityDSig::SHA1,
            ['http://www.w3.org/2000/09/xmldsig#enveloped-signature'],
            ['force_uri' => true]
        );

        // Create a new (private) Security key
        $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, ['type' => 'private']);
        // Load the private key
        $objKey->loadKey('D:\home\api\certs\votuporanga_privkey.pem', true);
        // Sign the XML file
        $objDSig->sign($objKey);
        // Add the associated public key to the signature
        $objDSig->add509Cert(file_get_contents('D:\home\api\certs\votuporanga_cert.crt'));
        if ($signRoot) {
            // Append the signature to the XML
            $objDSig->appendSignature($doc->documentElement);
        }
        foreach ($tags as $tag) {
            $rpsElements = $doc->getElementsByTagName($tag);
            foreach ($rpsElements as $rpsElement) {
                $objDSig->appendSignature($rpsElement);
            }
        }
        return $doc->saveXML();
    }
robrichards commented 5 years ago

Creating multiple signatures isn't currently supported, You might be able to work around this by playing around with the sigNode property but have never personally tried it

elvispdosreis commented 5 years ago

I still can not do with the "robrichards/xmlseclibs" package I'm using "nfephp-org/sped-common" that serves my purposes

tvdijen commented 5 years ago

A library from a commercial party that 1) doesn't know how to write English docs 2) doesn't know how to use coding standards 3) puts image resources in a low-level library and 4) hasn't taken the effort to write any unit-tests 5) has zero contributors... Hmmm, I think I'll pass, but thanks for the shameless self-promotion all over this repository! :wave:

Webdoors commented 4 years ago

please someone on earth help us

luizvaz commented 3 years ago

@elvispdosreis your code is almost right.

You need to remove the loop inside sign function that will append to all InfNfse tags with the same SIGNAGE.

Instead you need to loop over your XML and SIGN the first InfNfse tags.

Also remove ['force_uri' => true] and place [ 'id_name' => 'Id', 'overwrite' => false] instead.

Pass $signRoot = false too.

After all, just pass the $node where you want to append it like that:

   // Find the first node using NS
   $xpath = new DOMXPath($xml);
   $xpath->registerNamespace('ns', "http://www.abrasf.org.br/nfse.xsd");
   $node = $xpath->query("//ns:InfNfse")->item(0);
   if (!isset($node)) {
         $msg = "Tag <InfNfse> not found!";
         throw new Exception($msg);
    }

    $newXML = this.signXML($xml, false, $node)

...
public function signXml($xml, $signRoot = true, $node = null){
...
        // Sign using SHA-1
        $objDSig->addReference(
            ($node)?$node:$xml,
            XMLSecurityDSig::SHA1,
            ['http://www.w3.org/2000/09/xmldsig#enveloped-signature'],
            ['id_name' => 'Id', 'overwrite' => false]
        );
...
        if ($node) {
                $objDSig->appendSignature($node->parentNode);
        }
...

Cheers!