Sdk versions 3.2.6 and 3.3.3

Dear @Malik
For signing of XML invoice latest SDk 3.3.4 is used, but the certificates are generated using the CSR generated by OpenSSL . Whether it creates this issue “The invoice hash API body does not match the (calculated) Hash of the XML” ?

Dear @aymannagy, and @anusv

The mentioned error “The invoice hash API body does not match the (calculated) Hash of the XML” is received when the simplified tax invoice has been validated occurs because of a mistake in the signing process. Unlike standard tax invoice, simplified tax invoice & its associated notes must be signed with the taxpayer X.509 certificate (CSID), there are 2 returned X.509 certificates in the taxpayer’s EGS onboarding process.

First X.509 certificate: CCSID, which is returned after completing the first API (Compliance CSID), It’s returned as a security binary token which will be used as a username in the authorization, it’s also used as a signing certificate (X.509) after we decode it using base64 (we decode the binarysecurityToken) using base64 decoder and the output is the X.509 certificate, we use this certificate to sign the simplified tax invoices in the compliance invoice API (Compliance checks phase).

Second X.509 Certificate: PCSID, which is returned after completing the third API on the onboarding process (Production CSID), it’s also returned as a binary security token, and will be used as the username in te authorization for both reporting & clearance API, it’s also used as a signing certificate (X.509) after we decode it using base64 (we decode the binarysecurityToken) using base64 decoder and the output is the X.509 certificate, we use this certificate to sign the simplified tax invoices in the reporting API.

Please refer to the steps of manual signing using ZATCA’s JAVA SDK below:

1- After sending the CSR in the Compliance request CSID API, a Binarytoken & secret will be returned
2- Take the Binarytoken output, and decode it using base64 decoder, the decoded value is the x.509 certificate
3- Go to the SDK file to the following path: SDK/Data/Certificates/Cert.pem
4- Replace the value with your obtained x.509 certificate
5- Go to the JAVA SDK and use the command: fatoora -sign -invoice “invoice.xml”
6- Now the invoice will be signed & can be submitted successfully in the compliance checks phase (Compliance invoice API)
7- Redo the same steps above with the returned PCSID from the third API in the onboarding process and sign your simplified tax invoices with before sending to Reporting API

If you are implementing the signing process in your own code, please refer to the document of the “SigningProcessUpdated” which is attached to this mail.

If you require any additional support other than the mentioned steps above, please do not hesitate to reach out.

Dear @aymannagy ,

Please note that such details should not be posted on a public forum. Moreover, please make sure to use your own CSR file as the file contains specific information unique to your company such as Organization Identifier

This is a Dummy Data

@lalomar we are using .Net SDK. for signing the XML document. We are passing certificatecontent and privatekey as parameters. While signing upto “PopulateUBLExtensions” the steps are getting success. After that QR code is not generated in the 9th step. Upto 8th step it got success. No errors were shown in QR generation step.

Dear Mr. Malik

Can You tell me Why This Different Result When i Using Hash And i Have Invoice From Compliance Invoice API This is Hash Result :

f+0WCqnPkInI+eL9G3LAry12fTPf+toC9UX07F4fI+s= Portal

m8eDhcfHw/Nmt9vBYhGLL+fnFUO3q7VQNW7j3sT5X2E= SDK 3.3.4

m8eDhcfHw/Nmt9vBYhGLL+fnFUO3q7VQNW7j3sT5X2E= SDK 3.3.3

f+0WCqnPkInI+eL9G3LAry12fTPf+toC9UX07F4fI+s= SDK 3.3.2

Why it’s Different not Same Hash.

Hi,
Please do not compare with Sandbox instance and SDK 3.3.X both are latest and matching so you should use latest while not matching with 3.3.2 might be due to different certificates or any other challenge which I can’t comment better someone from ZATCA team can confirm if any validation difference causing it any other reason. thanks

The Latest Version Give me This Error Invoice Hash not match Calculated Hash

ok im Sorry For Compare and you know there is Something Wrong but i will be with you to End . Can You Tell me How to Fix This Error ?? before you Say Make Hash By Manual Code i Try To make it manual But There is Something Wrong because it gave me Different Value and This is My Code :
static String sha256_hash(String value)
{
StringBuilder Sb = new StringBuilder();

using (SHA256 hash = SHA256Managed.Create())
{
    Encoding enc = Encoding.UTF8;
    Byte[] result = hash.ComputeHash(enc.GetBytes(value));

    foreach (Byte b in result)
        Sb.Append(b.ToString("x2"));
}

return Sb.ToString();

}

static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}

XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(@“D:\AYman\Test.xml”);
#region Remove Tags
List xpath = new List()
{@“[local-name()=‘Invoice’]//[local-name()=‘UBLExtensions’]”,
@“//[local-name()=‘AdditionalDocumentReference’][cbc:ID[normalize-space(text()) = ‘QR’]]“,
@”
[local-name()=‘Invoice’]//*[local-name()=‘Signature’]”};
XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(xmlDocument.NameTable);
xmlNamespaceManager.AddNamespace(“cbc”, “urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2”);
foreach (var xpathItem in xpath)
{

var element = xmlDocument.SelectSingleNode(xpathItem, xmlNamespaceManager);
element.RemoveAll();

}
#endregion

#region Remove Version
if (xmlDocument.FirstChild.NodeType == XmlNodeType.XmlDeclaration)
xmlDocument.RemoveChild(xmlDocument.FirstChild);
#endregion
//xmlDocument.PreserveWhitespace = true;
using (MemoryStream obj3 = new MemoryStream(Encoding.UTF8.GetBytes(xmlDocument.OuterXml)))
{
XmlDsigC14NTransform xmlDsigC14NTransform = new XmlDsigC14NTransform(includeComments: false);
xmlDsigC14NTransform.LoadInput(obj3);
MemoryStream memoryStream = xmlDsigC14NTransform.GetOutput() as MemoryStream;
sbyte array2 = (from x in Sha256_hashAsBytes(Encoding.UTF8.GetString(memoryStream.ToArray()))
select (sbyte)x).ToArray();
var t = (byte)(object)array2;
string result = ToBase64Encode(System.Text.Encoding.UTF8.GetString(t));
Console.WriteLine(result);
}

Dear @aymannagy ,

Signing a document should not change the document Hash. The hashed document will always be the same before or after it is signed.

If you’re using .Net 8, maybe this Open Source Repository can help you. You can add the Zatca.eInvoice library project to your solution or copy the code into your project.

This library uses a small footprint, we can see how the library is used, and we just need to customize the project we create according to our needs.

I’ve tested this Repository on a Simulation Environment and so far, no issues.

Hope this can help you.

Thanx i will Check it

Dear eCloud

i Tested your Project But when I try to get Hash it Give me this Hash

YxaLIOFH0kWODHmy/V9C60OWCjdcPCyWJ39fq7WRM7I=

and it must be like This :

f+0WCqnPkInI+eL9G3LAry12fTPf+toC9UX07F4fI+s=

maybe i did something Wrong Can you Please Check it .

Best Regards
Ayman Ahmed

Dear Mr. Malik

Can You tell me Why This Different Result When i Using Hash And i Have Invoice From Compliance Invoice API This is Hash Result :

f+0WCqnPkInI+eL9G3LAry12fTPf+toC9UX07F4fI+s= Portal

m8eDhcfHw/Nmt9vBYhGLL+fnFUO3q7VQNW7j3sT5X2E= SDK 3.3.4

m8eDhcfHw/Nmt9vBYhGLL+fnFUO3q7VQNW7j3sT5X2E= SDK 3.3.3

f+0WCqnPkInI+eL9G3LAry12fTPf+toC9UX07F4fI+s= SDK 3.3.2

Why it’s Different not Same Hash.

Thanx For Your Fast Reply

I will Try Full Signed Invoice and Check Again if I Got the Same Problem or not

The invoice hash API body does not match the (calculated) Hash of the XML

Thanx alot

can you please Send me XML Invoice Example you Use ?

@aymannagy

Just use xml from Sample SDK to test. Its compliance with UBL2.1 and you can focus to get How to Signing Invoice.

If you just need to get Invoicehash, Signing Invoice, and Create Request Api for SignedDocument, you can simply use .Net Zatca.EInvoice.SDK.

Let me share the sample code.

  • Add Zatca.EInvoice.SDK and Zatca.EInvoice.SDK.Contracts as Assembly Reference
  • Add Rules files to your project folder.
...repos\ZatcaWithSDK\ZatcaWithSDK\Data\Rules\schematrons\20210819_ZATCA_E-invoice_Validation_Rules.xsl 
...repos\ZatcaWithSDK\ZatcaWithSDK\Data\Rules\schematrons\CEN-EN16931-UBL.xsl
  • Then you need cert.pem, ec-secp256k1-priv-key.pem and Simplified_Invoice.xml to test the SDK (i use this folder C:\Tmp\SdkTest\ for all myFiles)

{9EDFA059-985F-496A-B651-A764A44EB3A7}

using System.Xml;
using Zatca.EInvoice.SDK;
using Zatca.EInvoice.SDK.Contracts.Models;

namespace ZatcaWithSDK
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.OutputEncoding = System.Text.Encoding.UTF8;

            var eInvoicePath = @"C:\tmp\SdkTest\Simplified_Invoice.xml";
            var certificateFilePath = @"C:\tmp\SdkTest\cert.pem";
            var privateKeyFilePath = @"C:\tmp\SdkTest\ec-secp256k1-priv-key.pem";
            var signedPath = @"C:\tmp\SdkTest\Signed_Simplified_Invoice.xml";
            var jsonPath = @"C:\tmp\SdkTest\ApiRequestPayload.json";

            XmlDocument document = new XmlDocument() { PreserveWhitespace = true};
            document.Load(eInvoicePath);
            SignResult result = new EInvoiceSigner().SignDocument(document, File.ReadAllText(certificateFilePath), File.ReadAllText(privateKeyFilePath));

            ShowSignResult(result);

            if (result.IsValid)
            {
                result.SaveSignedEInvoice(signedPath);
                Console.WriteLine($"Invoice has been saved successfully\n");
                
                //Get Invoice Hash for Next PIH
                var SignedInvoiceHash = GetInvoiceHash(result);
                Console.WriteLine($"Invoice Hash : {SignedInvoiceHash}\n");

                //GetRequestApi Payload
                RequestGenerator RequestGenerator = new RequestGenerator();
                RequestResult RequestResult = RequestGenerator.GenerateRequest(result.SignedEInvoice);

                if (RequestResult.IsValid)
                {
                    RequestResult.SaveRequestToFile(jsonPath);
                    Console.WriteLine($"Request Api Payload : \n{ RequestResult.InvoiceRequest.Serialize()}");
                }
            }
        }

        public static string GetInvoiceHash(SignResult signResult)
        {
            var step = signResult.Steps
                .FirstOrDefault(s => s.StepName == "Generate EInvoice Hash");
            return step?.ResultedValue ?? "Invoice Hash not found";
        }

        public static void ShowSignResult(SignResult signResult)
        {

            foreach (var step in signResult.Steps)
            {
                Console.WriteLine($"Step: {step.StepName}");
                Console.WriteLine($"  Status: {(step.IsValid ? "Valid" : "Invalid")}");
                //Console.WriteLine($"  ResultValue: {step.ResultedValue}");

                if (step.ErrorMessages.Any())
                {
                    Console.WriteLine("  Errors:");
                    foreach (var error in step.ErrorMessages)
                    {
                        Console.WriteLine($"    - {error}");
                    }
                }

                if (step.WarningMessages.Any())
                {
                    Console.WriteLine("  Warnings:");
                    foreach (var warning in step.WarningMessages)
                    {
                        Console.WriteLine($"    - {warning}");
                    }
                }
            }

            Console.WriteLine();
            Console.WriteLine($"Overall Sign Result: {(signResult.IsValid ? "Valid" : "Invalid")}");
            Console.WriteLine();
        }

    }
}

This work good.

I am waiting for someone to provide a code example, how to validate Invoice using .Net Zatca.EInvoice.SDK Library.
So far I have not managed to do it. :slight_smile:

Dear @eCloud
Did you tried this code in simulation environment ? But @lalomar advised to hash the document after signing the invoice. While trying this code in simulation environment we are getting an error as “The invoice hash API body does not match the (calculated) Hash of the XML”. Please advise.

Dear @anusv ,

I think there was a misunderstanding, the signing process will automatically generate the hash and the QR code

Dear @lalomar
But while sending the invoice hash with signed XML geneated in signing process as Json object, ZATCA rejected with error “The invoice hash API body does not match the (calculated) Hash of the XML”.

Did you raise your concern to SP support? if yes please send a reminder email. If not, Can I kindly ask you to share your full concerns via email along with the XML file, the error message, and your signing process steps to the SP support team, to ensure comprehensive support, and schedule a meeting.

SP email: sp_support@zatca.gov.sa

Thanks,

Dear @lalomar
Will raise my concern through mail

Dear anusv

I was had this problem before. Forget To send email i send email before but no answer even i Call Customer Support They Told me to Go to Middleware Company . They Dont know How to Fix This Problem. Mr. eCloud is Good . And his Code helped me Alot .
now To Fix Your Problem By Using SDK .
1- Generate invoice.
2- Sign it.
3- Generate QR
4- Replace The Sign QR with New One That You Generated After you Did Sign Steps .
This Will Fix Hash Problem .

Note : Generate QR Have Problem That it Not Put Time and Date inside The QR . So its Good To Make Generate QR By Manual . All Required Data is inside the New Invoice.
Best Regards