robrichards / xmlseclibs

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

Problems with signign a part of an xml #225

Closed MartinWeidner closed 3 years ago

MartinWeidner commented 3 years ago

Hi, maybe it is a small issue, but I spent hours of coding and debugging...

I need the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<SignatureAuthentication xmlns="http://xxx.com">
    <SecurePart Id="fe09db4d-67b4-4c3a-a507-fdc323a99ecd">
        <ClientId>client</ClientId>
        <Timestamp>2021-01-26T10:10:30.977+01:00</Timestamp>
        <UrlEncodedRequest>
            ...
        </UrlEncodedRequest>
    </SecurePart>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
            <ds:Reference URI="#fe09db4d-67b4-4c3a-a507-fdc323a99ecd">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <ds:DigestValue>zTu3Ki3BBxtbjgl9qVrSxGezW/w=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
            Yv1k7gDLW7YH46LS.............
        </ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>
                    MIIDbTCCAlWgAw................
                </ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
</SignatureAuthentication>

So what I doing so far:

// Create XML
$request_data_SecurePart = ['SecurePart' =>
    [
        'ClientId' => $ClientId,
        'Timestamp' => date('Y-m-d') . 'T' . date('H:i:s'),
        'UrlEncodedRequest' => $UrlEncodedRequest
    ]
];

$a2x = new Array2XML();
$a2x->init('1.0', 'UTF-8', true, 'http://xxx.com');
$xml_temp = $a2x->createXML('SignatureAuthentication', $request_data_SecurePart);

// Create a new Security object
$objDSig = new XMLSecurityDSig();

// Use the c14n exclusive canonicalization
$objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);

// Sign using SHA-1
$objDSig->addReference(
    $xml_temp->documentElement,
    XMLSecurityDSig::SHA1,
    array('http://www.w3.org/2001/10/xml-exc-c14n#'),
);

// Create a new (private) Security key
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private'));

//If key has a passphrase, set it using
$objKey->passphrase = 'xxxxxx';

// Load the private key
$objKey->loadKey('private_key.pem', TRUE);

// Sign the XML file
$objDSig->sign($objKey);

// Add the associated public key to the signature
$objDSig->add509Cert(file_get_contents('keystore_certificate.pem'));

// Append the signature to the XML
$objDSig->appendSignature($xml_temp->documentElement);

// get XML
$xml = $xml_temp->SaveXML();

What I get:

<?xml version="1.0" encoding="UTF-8"?>
<SignatureAuthentication xmlns="http://xxx.com" Id="pfxfb00cca4-a09e-10e9-a01d-bad6159f8479">
    <SecurePart>
        <ClientId>12801703</ClientId>
        <Timestamp>2021-02-03T12:19:41</Timestamp>
        <UrlEncodedRequest>
            ...
        </UrlEncodedRequest>
    </SecurePart>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
            <ds:Reference URI="#pfxfb00cca4-a09e-10e9-a01d-bad6159f8479">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <ds:DigestValue>JZJk8Eo0yRoYlsA86arBrh+nKOg=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
            Yv1k7gDLW7YH46LS.............
        </ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>
                    MIIDbTCCAlWgAw................
                </ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
</SignatureAuthentication>

The Id="pfxfb... should be in SecurePart, not in SignatureAuthentication. How can I achive this?

Thanks in Advance.

Best Regards Martin

MartinWeidner commented 3 years ago

I've found the solution:

// Get SecurePart to sign
$SecurePart = $xml_temp->getElementsByTagName("SecurePart")->item(0);

// Sign using SHA-1
$objDSig->addReference(
    $SecurePart,
    XMLSecurityDSig::SHA1,
    array('http://www.w3.org/2001/10/xml-exc-c14n#'),
);

I extract the "SecurePart" node to sign.