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

Invalid signed properties hashing #44

Open
tawwfik opened this issue Aug 21, 2023 · 32 comments
Open

Invalid signed properties hashing #44

tawwfik opened this issue Aug 21, 2023 · 32 comments

Comments

@tawwfik
Copy link

tawwfik commented Aug 21, 2023

Error Invalid signed properties hashing, Signed Properties with id='xadesSignedProperties' during onboarding

@fuadhasni
Copy link

fuadhasni commented Aug 28, 2023 via email

@tawwfik
Copy link
Author

tawwfik commented Sep 13, 2023

` $template = "<xades:SignedProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" Id="xadesSignedProperties">
xades:SignedSignatureProperties
xades:SigningTimeSET_SIGN_TIMESTAMP</xades:SigningTime>
xades:SigningCertificate
xades:Cert
xades:CertDigest
<ds:DigestMethod xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">SET_CERTIFICATE_HASH</ds:DigestValue>
</xades:CertDigest>
xades:IssuerSerial
<ds:X509IssuerName xmlns:ds="http://www.w3.org/2000/09/xmldsig#">SET_CERTIFICATE_ISSUER</ds:X509IssuerName>
<ds:X509SerialNumber xmlns:ds="http://www.w3.org/2000/09/xmldsig#">SET_CERTIFICATE_SERIAL_NUMBER</ds:X509SerialNumber>
</xades:IssuerSerial>
</xades:Cert>
</xades:SigningCertificate>
</xades:SignedSignatureProperties>
</xades:SignedProperties>";

    $template = str_replace('SET_CERTIFICATE_HASH', $cert_info['hash'], $template);
    $template = str_replace('SET_SIGN_TIMESTAMP', $time, $template);
    $template = str_replace('SET_CERTIFICATE_SERIAL_NUMBER', $cert_info['serial_number'], $template);
    $template = str_replace('SET_CERTIFICATE_ISSUER', $cert_info['issuer'], $template);
    $hash=hash('sha256',$template);
   $signed_properties_hash = base64_encode($hash);`

these properties invalid hash the template is invalid

this response from zatca api
{ "type" => "ERROR", "code" => "signed-properties-hashing", "category" => "CERTIFICATE_ERRORS", "message" => "Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties'", "status" => "ERROR" }

@fawadsaboor
Copy link

@tawwfik Did you able to fix that issue?

@ktnasar
Copy link

ktnasar commented Nov 29, 2023

i have same issue can anybody help on it

@thaifanisalla
Copy link

thaifanisalla commented Nov 29, 2023

I have same issue in simulation mode

"errorMessages":[{"type":"ERROR","code":"GENERAL","category":"BUSINESS_RULES","message":"Unable to execute Business Rules validation ->BR-KSA-19","status":"ERROR"},{"type":"ERROR","code":"signed-properties-hashing","category":"CERTIFICATE_ERRORS","message":"Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties'","status":"ERROR"}],"status":"ERROR"},"reportingStatus":"NOT_REPORTED","clearanceStatus":null,"qrSellertStatus":null,"qrBuyertStatus":null

@tawwfik
Copy link
Author

tawwfik commented Dec 5, 2023

Hi guys.
I fixed the problem by register Namespace to Invoice Xml file.
after that
get the properties from invoice file.
this code laravel php solve problem.

                   $xml = new DOMDocument("1.0", "utf-8");
                     $xml->loadXML($invoice)// invoice file after populate the properties;
                   //use domPath to register this namespace
                   $xpath = new DOMXPath($xml);
                   //  register  namespace
                   $xpath->registerNamespace('default-ns', "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2");
                   $xpath->registerNamespace('sig', "urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-                                      
                   2");
                   $xpath->registerNamespace('sac',                    
                   "urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2");
                   $xpath->registerNamespace('sbc', "urn:oasis:names:specification:ubl:schema:xsd:SignatureBasicComponents-2");
                    $xpath->registerNamespace('ds', "http://www.w3.org/2000/09/xmldsig#");
                   $xpath->registerNamespace('xades', "http://uri.etsi.org/01903/v1.3.2#");
                   // path of SignedProperties
                   $SignedProperties = "//default-ns:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sig:UBLDocumentSignatures/sac:SignatureInformation/ds:Signature/ds:Object/xades:QualifyingProperties/xades:SignedProperties";
                   // get SignedProperties by path query
                   $SignedPropertiesValue = $xpath->query($SignedProperties);
                    // convert SignedProperties node to c14n standerd.
                   $canonicalizationInvoiceXML = $SignedPropertiesValue[0]->C14N(\true);
                   // replace tag to rquired in zatca.
                   $canonicalizationInvoiceXML = str_replace('></ds:DigestMethod>', '/>', $canonicalizationInvoiceXML);
                   // hash SignedProperties
                   $signed_properties_hash = base64_encode(hash('sha256', $canonicalizationInvoiceXML));

@Yottskry
Copy link

Sorry to resurrect an old thread, but I'm having the same issue. Could you show exactly what the SignedProperties section looks like just before you hash it, please? I'm still getting "Invalid signed properties hashing" every time.

@ajaybalachandran
Copy link

@Yottskry @fuadhasni @tawwfik @fawadsaboor @thaifanisalla

Issue 1: Inconsistency in E-Invoicing Statistics

After successfully integrating and following the official documentation provided by ZATCA, I have encountered an inconsistency in the e-invoicing statistics displayed on the Fatoora portal's simulation section. Despite receiving a "status":"PASS", "reportingStatus": "REPORTED" for submitted simplified invoices via the API endpoint "https://gw-fatoora.zatca.gov.sa/e-invoicing/simulation/invoices/reporting/single" and despite receiving a "status": "PASS", "clearanceStatus": "CLEARED" for standard invoices via "https://gw-fatoora.zatca.gov.sa/e-invoicing/simulation/invoices/clearance/single", the total count of submitted documents does not reflect accurately on the portal. This issue persists even after multiple checks over several days. Also, if I submitted and got a successful response from the API as the document is accepted and while checking on the Fatoora statistics page sometimes it is counted in rejected documents. Why is this mismatch happening? If I received REPORTED, CLEARED status with no error or warning messages, can I confirm that my document is submitted and accepted by ZATCA successfully? Please clarify this.

Issue 2: Lack of Clarity on Tax Amount Calculation

Additionally, I seek clarification on the calculation of the total tax amount payable to ZATCA for the submitted and accepted invoice documents. As there is no provision to retrieve this information from the ZATCA side, could you please confirm whether we need to calculate this amount internally based on the submitted invoices? For instance, if five invoices are successfully submitted and accepted, how do we determine the total tax amount owed to ZATCA?

Could someone please clarify these doubts?

@ajaybalachandran
Copy link

@tawwfik
I followed steps to obtain Production CSID in CORE API's from the official documentation and I got issuer name as given below
<ds:X509IssuerName>CN=PRZEINVOICESCA4-CA, DC=extgazt, DC=gov, DC=local</ds:X509IssuerName>
is this correct issuer name?

@owncommander
Copy link

owncommander commented Apr 16, 2024

hello
i'am facing the same problem with the same error message : "Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties"
but i'am using .NET DLL from zatca , (Zatca.EInvoice.SDK.dll + Zatca.EInvoice.SDK.Contracts.dll)
everything we need in these dll , hashing and signing invoice ,
This happen when calling API for invoice Complaince in Fatoora Simulation Portal
in Developer Portal never happen this error
can any one help me with that ?
And I thank you in advance

@Yottskry
Copy link

Yottskry commented Apr 16, 2024

hello i'am facing the same problem with the same error message : "Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties" but i'am using .NET DLL from zatca , (Zatca.EInvoice.SDK.dll + Zatca.EInvoice.SDK.Contracts.dll) everything we need in these dll , hashing and signing invoice , This happen when calling API for invoice Complaince in Fatoora Simulation Portal in Developer Portal never happen this error can any one help me with that ? And I thank you in advance

I also used the .net SDK and eventually got this working. The problem is that the XML has to be formatted exactly as Zatca expects because they also perform the hash at their end, so if we don't make the same manipulations they make they will get a different hash to us.

The steps I followed were:

  1. Sign the document using the SDK. Then obtain the xades:QualifyingProperties node using XPath
  2. Then get the InnerXML property as a string. You'll need to do string manipulation rather than relying on XML objects because you need to guarantee the order of attributes. We'll call this XmlString for now.
  3. Remove all xades:QualifyingProperties' children. This has the side effect of also removing its attributes, so you'll need to add in the Target property again (signode is the node found at 2):
signode.RemoveAll();
var xatt = xmldoc.CreateAttribute("Target");
xatt.Value = "signature";
signode.Attributes.Append(xatt);
  1. Ensure the attributes for XmlString's elements are in the right order. xmlns:ds="http://www.w3.org/2000/09/xmldsig#" must come first:
                  <xades:SignedProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" Id="xadesSignedProperties">
                    <xades:SignedSignatureProperties>
                      <xades:SigningTime>2024-04-16T09:50:23</xades:SigningTime>
                      <xades:SigningCertificate>
                        <xades:Cert>
                          <xades:CertDigest>
                            <ds:DigestMethod xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
                            <ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">YmJmMDdjZWQ0ZThkNTM3MjU2YTlhOGIwNTM4ZjBjMWQwYzMzNDJkZmNhZTBhOTUxNDE5NWFjM2RhZDg5NDczMQ==</ds:DigestValue>
                          </xades:CertDigest>
                          <xades:IssuerSerial>
                            <ds:X509IssuerName xmlns:ds="http://www.w3.org/2000/09/xmldsig#">CN=eInvoicing</ds:X509IssuerName>
                            <ds:X509SerialNumber xmlns:ds="http://www.w3.org/2000/09/xmldsig#">1712586866985</ds:X509SerialNumber>
                          </xades:IssuerSerial>
                        </xades:Cert>
                      </xades:SigningCertificate>
                    </xades:SignedSignatureProperties>
                  </xades:SignedProperties>
  1. Remove the space before the slash at the ends of any empty tags. i.e. replace:
    " \>" with "\>"
  2. Trim any newlines, carriage returns, or white space from the very beginning and end of XmlString (not from the individual lines, but from the string as a whole)
  3. Finally, replace any \r\n combinations with just \n. Lines should end with only newline.
  4. Now you'll need to hash XmlString, but you'll need to do it manually:
string finalstr;

// Hash the signature block.
using(var myhash = SHA256.Create())
{
  var hashval = myhash.ComputeHash(Encoding.UTF8.GetBytes(XmlString));
  StringBuilder builder = new StringBuilder();
  for (int i = 0; i < hashval.Length; i++)
  {
    builder.Append(hashval[i].ToString("x2"));
  }
  finalstr = Convert.ToBase64String(Encoding.UTF8.GetBytes(builder.ToString()));
}
  1. Replace the existing hash value with the one created in step 9:
xpathstr = "//ns:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sig:UBLDocumentSignatures/sac:SignatureInformation/ds:Signature/ds:SignedInfo/ds:Reference[position()=2]/ds:DigestValue";
signode = xmldoc.DocumentElement.SelectSingleNode(xpathstr, nsmgr);
signode.InnerText = finalstr;

One last thing is to remove the extra namespaces from the signature block or it won't validate the document correctly at Zatca, and to replace the entire signature block (removed in step 3) with our signature block. docstr is the entire document as a string (xmldoc.OuterXml):

chararray = new char[] { '\r', '\n' };
XmlString = XmlString.TrimStart(chararray);
XmlString = XmlString.Replace(" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\"", "");
docstr = docstr.Replace("</xades:QualifyingProperties>", "\n" + signodestr + "</xades:QualifyingProperties>");

It's a lot of hoops to jump through, and it took me about a week of trial and error to get here. I'm not saying this is the only way of doing this or even the best way, but this is what worked for me. I hope it at least puts you on the right track.

@owncommander
Copy link

owncommander commented Apr 17, 2024

hello i'am facing the same problem with the same error message : "Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties" but i'am using .NET DLL from zatca , (Zatca.EInvoice.SDK.dll + Zatca.EInvoice.SDK.Contracts.dll) everything we need in these dll , hashing and signing invoice , This happen when calling API for invoice Complaince in Fatoora Simulation Portal in Developer Portal never happen this error can any one help me with that ? And I thank you in advance

I also used the .net SDK and eventually got this working. The problem is that the XML has to be formatted exactly as Zatca expects because they also perform the hash at their end, so if we don't make the same manipulations they make they will get a different hash to us.

The steps I followed were:

  1. Sign the document using the SDK. Then obtain the xades:QualifyingProperties node using XPath
  2. Then get the InnerXML property as a string. You'll need to do string manipulation rather than relying on XML objects because you need to guarantee the order of attributes. We'll call this XmlString for now.
  3. Remove all xades:QualifyingProperties' children. This has the side effect of also removing its attributes, so you'll need to add in the Target property again (signode is the node found at 2):
signode.RemoveAll();
var xatt = xmldoc.CreateAttribute("Target");
xatt.Value = "signature";
signode.Attributes.Append(xatt);
  1. Ensure the attributes for XmlString's elements are in the right order. xmlns:ds="http://www.w3.org/2000/09/xmldsig#" must come first:
                  <xades:SignedProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" Id="xadesSignedProperties">
                    <xades:SignedSignatureProperties>
                      <xades:SigningTime>2024-04-16T09:50:23</xades:SigningTime>
                      <xades:SigningCertificate>
                        <xades:Cert>
                          <xades:CertDigest>
                            <ds:DigestMethod xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
                            <ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">YmJmMDdjZWQ0ZThkNTM3MjU2YTlhOGIwNTM4ZjBjMWQwYzMzNDJkZmNhZTBhOTUxNDE5NWFjM2RhZDg5NDczMQ==</ds:DigestValue>
                          </xades:CertDigest>
                          <xades:IssuerSerial>
                            <ds:X509IssuerName xmlns:ds="http://www.w3.org/2000/09/xmldsig#">CN=eInvoicing</ds:X509IssuerName>
                            <ds:X509SerialNumber xmlns:ds="http://www.w3.org/2000/09/xmldsig#">1712586866985</ds:X509SerialNumber>
                          </xades:IssuerSerial>
                        </xades:Cert>
                      </xades:SigningCertificate>
                    </xades:SignedSignatureProperties>
                  </xades:SignedProperties>
  1. Remove the space before the slash at the ends of any empty tags. i.e. replace:
    " \>" with "\>"
  2. Trim any newlines, carriage returns, or white space from the very beginning and end of XmlString (not from the individual lines, but from the string as a whole)
  3. Finally, replace any \r\n combinations with just \n. Lines should end with only newline.
  4. Now you'll need to hash XmlString, but you'll need to do it manually:
string finalstr;

// Hash the signature block.
using(var myhash = SHA256.Create())
{
  var hashval = myhash.ComputeHash(Encoding.UTF8.GetBytes(XmlString));
  StringBuilder builder = new StringBuilder();
  for (int i = 0; i < hashval.Length; i++)
  {
    builder.Append(hashval[i].ToString("x2"));
  }
  finalstr = Convert.ToBase64String(Encoding.UTF8.GetBytes(builder.ToString()));
}
  1. Replace the existing hash value with the one created in step 9:
xpathstr = "//ns:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sig:UBLDocumentSignatures/sac:SignatureInformation/ds:Signature/ds:SignedInfo/ds:Reference[position()=2]/ds:DigestValue";
signode = xmldoc.DocumentElement.SelectSingleNode(xpathstr, nsmgr);
signode.InnerText = finalstr;

One last thing is to remove the extra namespaces from the signature block or it won't validate the document correctly at Zatca, and to replace the entire signature block (removed in step 3) with our signature block. docstr is the entire document as a string (xmldoc.OuterXml):

chararray = new char[] { '\r', '\n' };
XmlString = XmlString.TrimStart(chararray);
XmlString = XmlString.Replace(" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\"", "");
docstr = docstr.Replace("</xades:QualifyingProperties>", "\n" + signodestr + "</xades:QualifyingProperties>");

It's a lot of hoops to jump through, and it took me about a week of trial and error to get here. I'm not saying this is the only way of doing this or even the best way, but this is what worked for me. I hope it at least puts you on the right track.

First of all, I would like to thank you very much for the explanation you provided ,
Second : i found the soluation in another DLL files named "SDKNETFrameWorkLib.dll" , this dll has also Sign and hash Method , and i replaced with the others in "Zatca.EInvoice.SDK.dll" , and it working very well
these methos are "EInvoiceSigningLogic" and "HashingValidator" , i expect these DLL's doing what you just explaining ....
thanks alot

@Yottskry
Copy link

First of all, I would like to thank you very much for the explanation you provided , Second : i found the soluation in another DLL files named "SDKNETFrameWorkLib.dll" , this dll has also Sign and hash Method , and i replaced with the others in "Zatca.EInvoice.SDK.dll" , and it working very well these methos are "EInvoiceSigningLogic" and "HashingValidator" , i expect these DLL's doing what you just explaining .... thanks alot

That's useful to know. We do have those DLL's but they were from an earlier version of the SDK. Perhaps they broke something in the newer versions? I'll have a look at them though, thanks.

@tawwfik
Copy link
Author

tawwfik commented Apr 24, 2024

this code for SignedProperties issue

it's work with me with php language

        $time = $this->dateFormat(new \DateTime());
        $template_xml = str_replace('SET_CERTIFICATE_HASH', $cert_info['hash'], $template_xml);
        $template_xml = str_replace('SET_SIGN_TIMESTAMP', $time, $template_xml);
        $template_xml = str_replace('SET_CERTIFICATE_SERIAL_NUMBER', $cert_info['serial_number'], $template_xml);
        $template_xml = str_replace('SET_CERTIFICATE_ISSUER', $cert_info['issuer'], $template_xml);
        $invoice = str_replace('<xades:SignedProperties/>', ($template_xml), $invoice);
        $invoice = str_replace('<?xml version="1.0"?>', '<?xml version="1.0" encoding="UTF-8"?>', $invoice);
        $xml = new DOMDocument("1.0", "utf-8");
        $xml->loadXML($invoice);
        $xpath = new DOMXPath($xml);
        $xpath->registerNamespace('default-ns', "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2");
        $SignedProperties = "//default-ns:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sig:UBLDocumentSignatures/sac:SignatureInformation/ds:Signature/ds:Object/xades:QualifyingProperties/xades:SignedProperties";
        $xpath->registerNamespace('sig', "urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-2");
        $xpath->registerNamespace('sac', "urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2");
        $xpath->registerNamespace('sbc', "urn:oasis:names:specification:ubl:schema:xsd:SignatureBasicComponents-2");
        $xpath->registerNamespace('ds', "http://www.w3.org/2000/09/xmldsig#");
        $xpath->registerNamespace('xades', "http://uri.etsi.org/01903/v1.3.2#");
        $SignedPropertiesValue = $xpath->query($SignedProperties);
        $canonicalizationInvoiceXML = $SignedPropertiesValue[0]->C14N(\true);
        $canonicalizationInvoiceXML = str_replace('></ds:DigestMethod>', '/>', $canonicalizationInvoiceXML);
        $signed_properties_hash = base64_encode(hash('sha256', $canonicalizationInvoiceXML));
        return [
            'signed_properties_hash' => $signed_properties_hash,
            'invoice' => $invoice,
        ];

$invoice is full invoice without SignedProperties tag
$template_xml is SignedProperties tag without data
after I add data to SignedProperties
add SignedProperties to full invoice
use xpath to get SignedProperties from full invoice not work if you not use xpath
you shoud use c14n when get SignedProperties by xpath

@tawwfik
Copy link
Author

tawwfik commented Apr 24, 2024

@tawwfik I followed steps to obtain Production CSID in CORE API's from the official documentation and I got issuer name as given below <ds:X509IssuerName>CN=PRZEINVOICESCA4-CA, DC=extgazt, DC=gov, DC=local</ds:X509IssuerName> is this correct issuer name?

@ajaybalachandran
yes is correct

@Wagdi-Noman
Copy link

Wagdi-Noman commented Apr 24, 2024

this code for SignedProperties issue

it's work with me with php language

        $time = $this->dateFormat(new \DateTime());
        $template_xml = str_replace('SET_CERTIFICATE_HASH', $cert_info['hash'], $template_xml);
        $template_xml = str_replace('SET_SIGN_TIMESTAMP', $time, $template_xml);
        $template_xml = str_replace('SET_CERTIFICATE_SERIAL_NUMBER', $cert_info['serial_number'], $template_xml);
        $template_xml = str_replace('SET_CERTIFICATE_ISSUER', $cert_info['issuer'], $template_xml);
        $invoice = str_replace('<xades:SignedProperties/>', ($template_xml), $invoice);
        $invoice = str_replace('<?xml version="1.0"?>', '<?xml version="1.0" encoding="UTF-8"?>', $invoice);
        $xml = new DOMDocument("1.0", "utf-8");
        $xml->loadXML($invoice);
        $xpath = new DOMXPath($xml);
        $xpath->registerNamespace('default-ns', "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2");
        $SignedProperties = "//default-ns:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sig:UBLDocumentSignatures/sac:SignatureInformation/ds:Signature/ds:Object/xades:QualifyingProperties/xades:SignedProperties";
        $xpath->registerNamespace('sig', "urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-2");
        $xpath->registerNamespace('sac', "urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2");
        $xpath->registerNamespace('sbc', "urn:oasis:names:specification:ubl:schema:xsd:SignatureBasicComponents-2");
        $xpath->registerNamespace('ds', "http://www.w3.org/2000/09/xmldsig#");
        $xpath->registerNamespace('xades', "http://uri.etsi.org/01903/v1.3.2#");
        $SignedPropertiesValue = $xpath->query($SignedProperties);
        $canonicalizationInvoiceXML = $SignedPropertiesValue[0]->C14N(\true);
        $canonicalizationInvoiceXML = str_replace('></ds:DigestMethod>', '/>', $canonicalizationInvoiceXML);
        $signed_properties_hash = base64_encode(hash('sha256', $canonicalizationInvoiceXML));
        return [
            'signed_properties_hash' => $signed_properties_hash,
            'invoice' => $invoice,
        ];

@tawwfik
Can you please provide more context so I can use this code in my project

  • What is the contents of the $invoice variable ? is it a full invoice including the UBL extension?.
  • what is the type of $template_xml .
    thank you in advance
    افدي الشنب

@tawwfik
Copy link
Author

tawwfik commented Apr 25, 2024

this code for SignedProperties issue
it's work with me with php language

        $time = $this->dateFormat(new \DateTime());
        $template_xml = str_replace('SET_CERTIFICATE_HASH', $cert_info['hash'], $template_xml);
        $template_xml = str_replace('SET_SIGN_TIMESTAMP', $time, $template_xml);
        $template_xml = str_replace('SET_CERTIFICATE_SERIAL_NUMBER', $cert_info['serial_number'], $template_xml);
        $template_xml = str_replace('SET_CERTIFICATE_ISSUER', $cert_info['issuer'], $template_xml);
        $invoice = str_replace('<xades:SignedProperties/>', ($template_xml), $invoice);
        $invoice = str_replace('<?xml version="1.0"?>', '<?xml version="1.0" encoding="UTF-8"?>', $invoice);
        $xml = new DOMDocument("1.0", "utf-8");
        $xml->loadXML($invoice);
        $xpath = new DOMXPath($xml);
        $xpath->registerNamespace('default-ns', "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2");
        $SignedProperties = "//default-ns:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sig:UBLDocumentSignatures/sac:SignatureInformation/ds:Signature/ds:Object/xades:QualifyingProperties/xades:SignedProperties";
        $xpath->registerNamespace('sig', "urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-2");
        $xpath->registerNamespace('sac', "urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2");
        $xpath->registerNamespace('sbc', "urn:oasis:names:specification:ubl:schema:xsd:SignatureBasicComponents-2");
        $xpath->registerNamespace('ds', "http://www.w3.org/2000/09/xmldsig#");
        $xpath->registerNamespace('xades', "http://uri.etsi.org/01903/v1.3.2#");
        $SignedPropertiesValue = $xpath->query($SignedProperties);
        $canonicalizationInvoiceXML = $SignedPropertiesValue[0]->C14N(\true);
        $canonicalizationInvoiceXML = str_replace('></ds:DigestMethod>', '/>', $canonicalizationInvoiceXML);
        $signed_properties_hash = base64_encode(hash('sha256', $canonicalizationInvoiceXML));
        return [
            'signed_properties_hash' => $signed_properties_hash,
            'invoice' => $invoice,
        ];

@tawwfik Can you please provide more context so I can use this code in my project

  • What is the contents of the $invoice variable ? is it a full invoice including the UBL extension?.
  • what is the type of $template_xml .
    thank you in advance
    افدي الشنب

$invoice is full invoice without SignedProperties tag
$template_xml is SignedProperties tag without data
after I add data to SignedProperties
add SignedProperties to full invoice
use xpath to get SignedProperties from full invoice not work if you not use xpath
you shoud use c14n when get SignedProperties by xpath

@Wagdi-Noman
Copy link

@tawwfik full invoice including the UBL Extension only without the `SignedProperties'!
thank you.

@aafi53
Copy link

aafi53 commented May 23, 2024

Hey , i'm facing this issue , anybody can help me ,code":"invalid-invoice-hash","category":"INVOICE_HASHING_ERRORS","message":"The invoice hash API body does not match the (calculated) Hash of the XML (PHP)

@owncommander
Copy link

i face this issue before , the reason was i didn't encode the xml to UTF8 before converting to base64 , because i'am using Arabic Letters

@aafi53
Copy link

aafi53 commented May 24, 2024

i face this issue before , the reason was i didn't encode the xml to UTF8 before converting to base64 , because i'am using Arabic Letters

can you share me some code example, because hash created from my side is not same like created by sdk..

@owncommander
Copy link

i face this issue before , the reason was i didn't encode the xml to UTF8 before converting to base64 , because i'am using Arabic Letters

can you share me some code example, because hash created from my side is not same like created by sdk..

after Signing the XML for invoice ... generate hash by using this :
HashingValidator ihash = new HashingValidator();
Result hr_g = new Result();
Result hr_v = new Result();
XmlDocument SignedXML = new XmlDocument();
invFileName = vvat_no + "" + vdate.Replace("-", "") + "T" + vtime.Replace(":", "") + "" + vinvno;
SignedXMLPath = File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + @"\Invoices\Signed" + invFileName + ".xml");
SignedXML.LoadXml(SignedXMLPath);

            hr_g = ihash.GenerateEInvoiceHashing(SignedXMLPath);
            hr_v = ihash.ValidateEInvoiceHashing(SignedXMLPath);
            if (hr_v.IsValid)
            {
                ih = hr_g.ResultedValue;
            }

and i saved the uuid and hash into out system database ....
then when report or clear the invoice to zatca i used this ::
string i = File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + @"\Invoices\Signed" + invFileName + ".xml"); // For read all xml file into string variable
string invb64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(i)); // to Encode all invoice to UTF8 and the convert it to base64


i hope that can help you

@aafi53
Copy link

aafi53 commented May 24, 2024

i face this issue before , the reason was i didn't encode the xml to UTF8 before converting to base64 , because i'am using Arabic Letters

can you share me some code example, because hash created from my side is not same like created by sdk..

after Signing the XML for invoice ... generate hash by using this : HashingValidator ihash = new HashingValidator(); Result hr_g = new Result(); Result hr_v = new Result(); XmlDocument SignedXML = new XmlDocument(); invFileName = vvat_no + "" + vdate.Replace("-", "") + "T" + vtime.Replace(":", "") + "" + vinvno; SignedXMLPath = File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + @"\Invoices\Signed" + invFileName + ".xml"); SignedXML.LoadXml(SignedXMLPath);

            hr_g = ihash.GenerateEInvoiceHashing(SignedXMLPath);
            hr_v = ihash.ValidateEInvoiceHashing(SignedXMLPath);
            if (hr_v.IsValid)
            {
                ih = hr_g.ResultedValue;
            }

and i saved the uuid and hash into out system database .... then when report or clear the invoice to zatca i used this :: string i = File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + @"\Invoices\Signed" + invFileName + ".xml"); // For read all xml file into string variable string invb64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(i)); // to Encode all invoice to UTF8 and the convert it to base64

i hope that can help you

thank you, but still i'm getting same error , do you have any php code example in which you generated hash of invoice from xml

@owncommander
Copy link

sorry , but i'am using c#

@aafi53
Copy link

aafi53 commented May 25, 2024

Hi guys. I fixed the problem by register Namespace to Invoice Xml file. after that get the properties from invoice file. this code laravel php solve problem.

                   $xml = new DOMDocument("1.0", "utf-8");
                     $xml->loadXML($invoice)// invoice file after populate the properties;
                   //use domPath to register this namespace
                   $xpath = new DOMXPath($xml);
                   //  register  namespace
                   $xpath->registerNamespace('default-ns', "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2");
                   $xpath->registerNamespace('sig', "urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-                                      
                   2");
                   $xpath->registerNamespace('sac',                    
                   "urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2");
                   $xpath->registerNamespace('sbc', "urn:oasis:names:specification:ubl:schema:xsd:SignatureBasicComponents-2");
                    $xpath->registerNamespace('ds', "http://www.w3.org/2000/09/xmldsig#");
                   $xpath->registerNamespace('xades', "http://uri.etsi.org/01903/v1.3.2#");
                   // path of SignedProperties
                   $SignedProperties = "//default-ns:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sig:UBLDocumentSignatures/sac:SignatureInformation/ds:Signature/ds:Object/xades:QualifyingProperties/xades:SignedProperties";
                   // get SignedProperties by path query
                   $SignedPropertiesValue = $xpath->query($SignedProperties);
                    // convert SignedProperties node to c14n standerd.
                   $canonicalizationInvoiceXML = $SignedPropertiesValue[0]->C14N(\true);
                   // replace tag to rquired in zatca.
                   $canonicalizationInvoiceXML = str_replace('></ds:DigestMethod>', '/>', $canonicalizationInvoiceXML);
                   // hash SignedProperties
                   $signed_properties_hash = base64_encode(hash('sha256', $canonicalizationInvoiceXML));

Bro how you generated InvoiceHash in php ?
or3rT7i9zH/YB9b2TkIGT9w1ysISfcckyHpGMSGRVyA= i created invoiceHash by sdk
drYi8GYkrOhTk2CzX6MMOUIOtgCz4qJuTaE+FfpZ0lE= this i generated by Php code, when i pass First Hash generated By SDK i didn't get error, but second Invoice Hash shows error, so i get error my error in InvoiceHash, Can you help me in this Regards..

@Faheemmcfc
Copy link

I am trying to pass Simplified Invoice (B2C) for compliance. But it's giving me following errors:

Invalid certificate hashing
Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties'

I am using the same procedure for Standard Invoice(B2B) for compliance and it's working very fine. I am using .Net SDK for implementation.
Validation of the xml with ZATCA SDK is successful. But when passing the invoice to Compliance Invoice API producing above errors.
Only difference in Simplified and Standard invoice is that, simplified invoice have 'InvoiceTypeCode = 020000', but in Standard Invoice it is 'InvoiceTypeCode=010000'.

Trying to get a solution for a long time.

Please help.
Thank you..

@owncommander
Copy link

I am trying to pass Simplified Invoice (B2C) for compliance. But it's giving me following errors:

Invalid certificate hashing
Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties'

I am using the same procedure for Standard Invoice(B2B) for compliance and it's working very fine. I am using .Net SDK for implementation. Validation of the xml with ZATCA SDK is successful. But when passing the invoice to Compliance Invoice API producing above errors. Only difference in Simplified and Standard invoice is that, simplified invoice have 'InvoiceTypeCode = 020000', but in Standard Invoice it is 'InvoiceTypeCode=010000'.

Trying to get a solution for a long time.

Please help. Thank you..

i was facing these errors before .... the soluation i did is using Old Zatca dll because i'am using .NET like you .... this dll called "SDKNETFrameWorkLib.dll" ... i used this dll for Signing the invoice and "Zatca.EInvoice.SDK.dll" for QR Generating .
another note :
for complaince using (CCSID) (responce from zatca when send CSR) and for reporting using (PCSID) (when send token+secret+request id from csid)
this is link for the old dll : https://www.mediafire.com/file/b7j52okvygc8v3p/SDKNETFrameWorkLib.dll/file
i hope that can help
best wishes

@Faheemmcfc
Copy link

I am trying to pass Simplified Invoice (B2C) for compliance. But it's giving me following errors:

Invalid certificate hashing
Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties'

I am using the same procedure for Standard Invoice(B2B) for compliance and it's working very fine. I am using .Net SDK for implementation. Validation of the xml with ZATCA SDK is successful. But when passing the invoice to Compliance Invoice API producing above errors. Only difference in Simplified and Standard invoice is that, simplified invoice have 'InvoiceTypeCode = 020000', but in Standard Invoice it is 'InvoiceTypeCode=010000'.
Trying to get a solution for a long time.
Please help. Thank you..

i was facing these errors before .... the soluation i did is using Old Zatca dll because i'am using .NET like you .... this dll called "SDKNETFrameWorkLib.dll" ... i used this dll for Signing the invoice and "Zatca.EInvoice.SDK.dll" for QR Generating . another note : for complaince using (CCSID) (responce from zatca when send CSR) and for reporting using (PCSID) (when send token+secret+request id from csid) this is link for the old dll : https://www.mediafire.com/file/b7j52okvygc8v3p/SDKNETFrameWorkLib.dll/file i hope that can help best wishes

Tried this dll, but hashing function is not working. Code is below:
var _IHashingValidator = new SDKNETFrameWorkLib.BLL.HashingValidator(); Result objResult = new Result(); objResult = _IHashingValidator.GenerateEInvoiceHashing(location);

I think this dll doen't have that function. How you are doing the hashing of the xml?
Can you help.
Thank you..

@owncommander
Copy link

this for hashing :
SDKNETFrameWorkLib.BLL.HashingValidator ihash = new SDKNETFrameWorkLib.BLL.HashingValidator();
SDKNETFrameWorkLib.GeneralLogic.Result hr_g = new SDKNETFrameWorkLib.GeneralLogic.Result();
SDKNETFrameWorkLib.GeneralLogic.Result hr_v = new SDKNETFrameWorkLib.GeneralLogic.Result();
XmlDocument SignedXML = new XmlDocument();
invFileName = vvat_no + "" + vdate.Replace("-", "") + "T" + vtime.Replace(":", "") + "" + vinvno;
SignedXMLPath = File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + @"\Invoices\Signed" + invFileName + ".xml");
SignedXML.LoadXml(SignedXMLPath);

            hr_g = ihash.GenerateEInvoiceHashing(SignedXMLPath);
            hr_v = ihash.ValidateEInvoiceHashing(SignedXMLPath);
            if (hr_v.IsValid)
            {
                //if (flag == 2) { Console.WriteLine("Invoice Hashing Successfully ....."); }
                ih = hr_g.ResultedValue;
            }
        }
        catch (Exception ErrorHasing)
        {
            File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + @"\Errors\Err_Hash_" + invFileName + ".txt", ErrorHasing.Message);
        }

@Faheemmcfc
Copy link

this for hashing : SDKNETFrameWorkLib.BLL.HashingValidator ihash = new SDKNETFrameWorkLib.BLL.HashingValidator(); SDKNETFrameWorkLib.GeneralLogic.Result hr_g = new SDKNETFrameWorkLib.GeneralLogic.Result(); SDKNETFrameWorkLib.GeneralLogic.Result hr_v = new SDKNETFrameWorkLib.GeneralLogic.Result(); XmlDocument SignedXML = new XmlDocument(); invFileName = vvat_no + "" + vdate.Replace("-", "") + "T" + vtime.Replace(":", "") + "" + vinvno; SignedXMLPath = File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + @"\Invoices\Signed" + invFileName + ".xml"); SignedXML.LoadXml(SignedXMLPath);

            hr_g = ihash.GenerateEInvoiceHashing(SignedXMLPath);
            hr_v = ihash.ValidateEInvoiceHashing(SignedXMLPath);
            if (hr_v.IsValid)
            {
                //if (flag == 2) { Console.WriteLine("Invoice Hashing Successfully ....."); }
                ih = hr_g.ResultedValue;
            }
        }
        catch (Exception ErrorHasing)
        {
            File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + @"\Errors\Err_Hash_" + invFileName + ".txt", ErrorHasing.Message);
        }

Tried your solution, but couldn't get it right. Hash is not valid after using your method. can I hash the xml without making it as a string.

@glow2590
Copy link

glow2590 commented Jul 1, 2024

Hi guys. I fixed the problem by register Namespace to Invoice Xml file. after that get the properties from invoice file. this code laravel php solve problem.

                   $xml = new DOMDocument("1.0", "utf-8");
                     $xml->loadXML($invoice)// invoice file after populate the properties;
                   //use domPath to register this namespace
                   $xpath = new DOMXPath($xml);
                   //  register  namespace
                   $xpath->registerNamespace('default-ns', "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2");
                   $xpath->registerNamespace('sig', "urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-                                      
                   2");
                   $xpath->registerNamespace('sac',                    
                   "urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2");
                   $xpath->registerNamespace('sbc', "urn:oasis:names:specification:ubl:schema:xsd:SignatureBasicComponents-2");
                    $xpath->registerNamespace('ds', "http://www.w3.org/2000/09/xmldsig#");
                   $xpath->registerNamespace('xades', "http://uri.etsi.org/01903/v1.3.2#");
                   // path of SignedProperties
                   $SignedProperties = "//default-ns:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sig:UBLDocumentSignatures/sac:SignatureInformation/ds:Signature/ds:Object/xades:QualifyingProperties/xades:SignedProperties";
                   // get SignedProperties by path query
                   $SignedPropertiesValue = $xpath->query($SignedProperties);
                    // convert SignedProperties node to c14n standerd.
                   $canonicalizationInvoiceXML = $SignedPropertiesValue[0]->C14N(\true);
                   // replace tag to rquired in zatca.
                   $canonicalizationInvoiceXML = str_replace('></ds:DigestMethod>', '/>', $canonicalizationInvoiceXML);
                   // hash SignedProperties
                   $signed_properties_hash = base64_encode(hash('sha256', $canonicalizationInvoiceXML));

Thank you so much mate <3

@mranonyms022
Copy link

mranonyms022 commented Jul 4, 2024

Hi guys. I fixed the problem by register Namespace to Invoice Xml file. after that get the properties from invoice file. this code laravel php solve problem.

                   $xml = new DOMDocument("1.0", "utf-8");
                     $xml->loadXML($invoice)// invoice file after populate the properties;
                   //use domPath to register this namespace
                   $xpath = new DOMXPath($xml);
                   //  register  namespace
                   $xpath->registerNamespace('default-ns', "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2");
                   $xpath->registerNamespace('sig', "urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-                                      
                   2");
                   $xpath->registerNamespace('sac',                    
                   "urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2");
                   $xpath->registerNamespace('sbc', "urn:oasis:names:specification:ubl:schema:xsd:SignatureBasicComponents-2");
                    $xpath->registerNamespace('ds', "http://www.w3.org/2000/09/xmldsig#");
                   $xpath->registerNamespace('xades', "http://uri.etsi.org/01903/v1.3.2#");
                   // path of SignedProperties
                   $SignedProperties = "//default-ns:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sig:UBLDocumentSignatures/sac:SignatureInformation/ds:Signature/ds:Object/xades:QualifyingProperties/xades:SignedProperties";
                   // get SignedProperties by path query
                   $SignedPropertiesValue = $xpath->query($SignedProperties);
                    // convert SignedProperties node to c14n standerd.
                   $canonicalizationInvoiceXML = $SignedPropertiesValue[0]->C14N(\true);
                   // replace tag to rquired in zatca.
                   $canonicalizationInvoiceXML = str_replace('></ds:DigestMethod>', '/>', $canonicalizationInvoiceXML);
                   // hash SignedProperties
                   $signed_properties_hash = base64_encode(hash('sha256', $canonicalizationInvoiceXML));

Thank you so much mate <3

Will you please provide me some support regarding this I am facing the same Issue I did everything as per the document but I am still getting invoice hashing error.Please help me out

errorMessages": array:1 [
0 => {#1506
+"type": "ERROR"
+"code": "invalid-invoice-hash"
+"category": "INVOICE_HASHING_ERRORS"
+"message": "The invoice hash API body does not match the (calculated) Hash of the XML"
+"status": "ERROR"
}
]
+"status": "ERROR"
}

I am getting this error in laravel

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