Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signatures done with XMLSecurityDSig do not pass C# DOTNET validation #247

Open
guycalledseven opened this issue Feb 2, 2023 · 0 comments

Comments

@guycalledseven
Copy link

guycalledseven commented Feb 2, 2023

I have been successfully using xmlseclibs package up until one point. I had to sign xml and one specific c# endpoint had to validate it, and validation was failing. No matter my signed xml document passed internal xmlseclibs validation, even validation in java endpoint and online http://tools.chilkat.io/xmlDsigVerify.cshtml web checker.

I've spent many hours on debugging this issue and finally found out that culprit for failing checks was a whitespace in signature template, namely:

    const template = '<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:SignedInfo>
    <ds:SignatureMethod />
  </ds:SignedInfo>
</ds:Signature>';

    const BASE_TEMPLATE = '<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
    <SignatureMethod />
  </SignedInfo>
</Signature>';

...

public function __construct($prefix='ds')
{
...
    $sigdoc = new DOMDocument();
    $sigdoc->loadXML($template);
    $this->sigNode = $sigdoc->documentElement;
...

If xml you are trying to sign xml that has whitespace = false, and this signature with whitespace is added - it freaks out DOTNETs System.Security.Cryptography.Xml.SignedXml; CheckSignature method if DOTNET side does not have whitespace or significantWhitespace properties defined (my working theory, maybe it's also connected with something how DOTNET handles EXC_C14N cannonization ):

using System.Security.Cryptography.X509Certificates;
using static System.Security.Cryptography.Xml.SignedXml;
using System.Security.Cryptography.Xml;
...
            // Load the signature node into a new XML document
            XmlDocument signatureXmlDoc = new XmlDocument();
            signatureXmlDoc.LoadXml(nodeList[0].OuterXml);

            // Create a new instance of the XML signature object
            SignedXml signedXml = new SignedXml(xmlDoc);

            // Load the signature node into the signed XML object
            signedXml.LoadXml(signatureXmlDoc.DocumentElement);

            // Verify the signature
            return signedXml.CheckSignature(rsaKey);
...

So the solution is to strip whitespace out of everything before signing:

  1. xml you are trying to sign
  2. added signature node

Simplified example on how I signed this document with XMLSecurityDSig:

$xml = '<?xml version="1.0" encoding="utf-8"?><ServiceResponse xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ServiceData></ServiceData><Signatures></Signatures></ServiceResponse>';

$xmlDocument = new DOMDocument('1.0', 'UTF-8');
$xmlDocument->formatOutput = false;
$xmlDocument->preserveWhiteSpace = false;
$xmlDocument->loadXML($xml);

$serviceresponse_node = $xmlDocument->getElementsByTagName("ServiceResponse")->item(0);
$objDSig = new XMLSecurityDSig('');
$objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N); // relaxed about SignedInfo

$objDSig->addReference(
	$serviceresponse_node,
	XMLSecurityDSig::SHA1, // 'http://www.w3.org/2000/09/xmldsig#sha1',
	['http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#'],
	['id_name' => 'Id', 'overwrite' => false],
);

$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type'=>'private'));
$objKey->loadKey($this->privateCertPath, TRUE);

$objDSig->sign($objKey, $xmlDocument->documentElement);
$objDSig->add509Cert(file_get_contents($this->publicCertPath));

$signatures_node = $xmlDocument->getElementsByTagName("Signatures")->item(0);
$objDSig->appendSignature($signatures_node);
$signedXML = $xmlDocument->saveXML();

edit: php/c# examples

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant