robrichards / xmlseclibs

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

Set URI attribute with a fixed value #234

Closed sabas closed 8 months ago

sabas commented 2 years ago

In https://github.com/robrichards/xmlseclibs/blob/master/src/XMLSecurityDSig.php#L662 I needed to change the line to read $refNode->setAttribute("URI", '#'.$id_name) Because I was trying to reproduce an XML which has

  <attachment id="attachmentId">[data]</attachment>

and below <ds:Reference URI="#attachmentId">

BanalitoRaulito commented 1 year ago

Hello @robrichards!

I've the same question/issue. I believe its already possible to sign a only a part of xml (with this libary) and it will get reflected in "Reference".

I'm looking for solution that will only sign a part of the xml file.

@sabas did you find a solution for this?

sabas commented 1 year ago

@BanalitoRaulito I was in a rush to complete the thing and I simply commented out the if block here https://github.com/robrichards/xmlseclibs/blob/master/src/XMLSecurityDSig.php#L650

        /*
        if (! $node instanceof DOMDocument) {
            $uri = null;
            if (! $overwrite_id) {
                $uri = $prefix_ns ? $node->getAttributeNS($prefix_ns, $id_name) : $node->getAttribute($id_name);
            }
            if (empty($uri)) {
                $uri = self::generateGUID();
                $node->setAttributeNS($prefix_ns, $attname, $uri);
            }
            $refNode->setAttribute("URI", '#'.$uri);
        } elseif ($force_uri) {
            $refNode->setAttribute("URI", '#'.$uri);
        }
        */

        $refNode->setAttribute("URI", '#'.$id_name);

I hope it helps somehow :-)

BanalitoRaulito commented 1 year ago
        $doc = new \DOMDocument();
        $doc->loadXML('hole xml content');
        $element = $doc->getElementsByTagName('SignedProperties');

        $objDSig = new XMLSecurityDSig();

        $objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);

        $objDSig->addReference(
            $element[0],
            XMLSecurityDSig::SHA256,
            null,
            [
                'id_name' => 'id',
                'overwrite' => true,
            ]
        );

        $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, ['type' => 'private']);
        $objKey->loadKey(base_path(...), true);
        $objDSig->sign($objKey);
        $objDSig->add509Cert(file_get_contents(...));
        $objDSig->appendSignature($doc->documentElement);

I managed to get it working!

The element in xml I wanted to sign is called "SignedProperties" and it has property id (note 'id_name' value in addReference). addReference first value must be a DOMElement (not DOMDocument) to make use of this functionality.

sabas commented 8 months ago

Managed to review this after an upgrade broke again my patchwork :D @BanalitoRaulito nice hint, that was the DOMElement, plus the id_name wasn't the one to be inserted in the document but the id of the existing element In my case the xml to be signed contained this element

    $attachment = $xml->createElement('attachment', $attachment1);
    $attachment->setAttribute('id', 'attachmentId');
    $root->appendChild($attachment);

And the correct way to sign this is

    $objXMLSecDSig = new XmlSecurityDSig();
    $objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);

    $objXMLSecDSig->addReference(
        $xml->getElementsByTagName('attachment')[0],
        XMLSecurityDSig::SHA256,
        [
            [
                'http://www.w3.org/TR/1999/REC-xpath-19991116' => [
                    'query' => "*[@id='attachmentId']",
                    'namespaces' => [
                        'ds' => 'http://www.w3.org/2000/09/xmldsig#',
                    ],
                ],
            ],
            'http://www.w3.org/2000/09/xmldsig#enveloped-signature',
            'http://www.w3.org/2001/10/xml-exc-c14n#WithComments',
        ],
        [
            'overwrite' => false,
            'id_name' => 'id',
            'prefix_ns' => false
        ]
    );