Simplified signed xml validation issue

I followed the signing process document to sign the simplified invoice. However, when I validate the signed XML using the sandbox validator, I receive the following validation error:
but the same signed xml is validated successfully for standard invoice.

Errors

  • category : SIGNATURE_ERROR

  • **code :**xadesSignedPropertiesDigestValue

  • message : wrong xadesSignedPropertiesDigestValue

  • category : SIGNATURE_ERROR

  • **code :**X509IssuerName

  • message : wrong X509IssuerName

  • category : SIGNATURE_ERROR

  • **code :**signatureValue

  • message : wrong signature Value

  • category : SIGNATURE_ERROR

  • **code :**signingCertificateDigestValue

  • message : wrong signingCertificateDigestValue

Dear @Biplab1 validating Simplified Invoice on web-based validator will always show signature error as web validator validates using a certificate different from the one used for signing Simplified Invoice. Therefore, validating Simplified Invoice using web-based validator will give a certificate validation error which is expected behavior. As you are aware, Simplified Invoices are not required to be shared in XML format with customer, therefore, customers are not expected to validate Simplified Invoices using web-based validator. Developers have SDK, Sandbox and Simulation Portal to validate Simplified Invoices. You can ignore certificate errors on Simplified Invoice while validating them on web-based validator.

Check earlier post on similar topic

Thank you for the clarification regarding Simplified Invoice validation on the web-based validator. I understand that signature validation errors are expected there due to the use of a different certificate than the one used for signing.

However, I have chosen to skip web-based validation and proceeded to validate via the ZATCA Reporting API (sandbox environment). While calling the /reporting/simplifiedInvoices API, I’m receiving a 400 response with the following validation errors:

{“validationResults”:{“infoMessages”:[{“type”:“INFO”,“code”:“XSD_ZATCA_VALID”,“category”:“XSD validation”,“message”:“Complied with UBL 2.1 standards in line with ZATCA specifications”,“status”:“PASS”}],“warningMessages”:[{“type”:“WARNING”,“code”:“certificate-issuer-name”,“category”:“CERTIFICATE_ERRORS”,“message”:“X509Certificate (CCSID / PCSID) used for signing is not valid certificate (CCSID / PCSID) for this VAT Registration Number.”,“status”:“WARNING”}],“errorMessages”:[{“type”:“ERROR”,“code”:“certificate-signing-time-format”,“category”:“CERTIFICATE_ERRORS”,“message”:“Invalid signing time format”,“status”:“ERROR”},{“type”:“ERROR”,“code”:“certificate-hashing”,“category”:“CERTIFICATE_ERRORS”,“message”:“Invalid certificate hashing”,“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”}

This suggests that the issue may not be limited to web-based validation, as the Reporting API itself is returning critical certificate and signature-related errors. I would appreciate any guidance on addressing these specific issues.

Thanks in advance for your support.

@Biplab1 Sandbox portal has a static CSID and it is not meant for testing using your PCSIDs. If you wish to test using your own PCSID, please onboard PCSID on Simulation Environment and test it there.

Dear @Ankit.K.Tiwari ,
Thanks for your response.
when i do compliance check for simplified invoice in sandbox mode ,i get response as Reported but for reporting api i get validation error
can you please guide to resolve this.

Dear @Ankit.K.Tiwari,
I have generated Ccsid and Pcsid in sandbox environment.
can i test simplified invoice reporting in sandbox environment ?

Dear @Biplab1 , as it was stated by @Ankit.K.Tiwari , you should not use SandBox environment for validation and you should not use it at all.

Short history: when ZATCA released first version of API they had only production environment and sandbox. The sandbox does not allow you to generate certificates and use “hardcoded” certificate. Originally “sandbox” environment was the only way to test the integration steps but due to limitations mentioned above - it could not be used to test the full flow.

Later on ZATCA added “simulation” environment, where you can test the full flow including onboarding the device and reporting using it. Nowadays “sandbox” environment should not be used (IMHO) or should be used ONLY for initial code implementation (if you are writing your own API client without usage of SDK).

Now the main advice, START using “simulation” for all your testing and STOP using “sandbox”. If you have any issues with “simulation” it means you probably will have the same issues on production.

If you have any more questions, you can reply on this message and I will try to help you.

Dear @sergei.shishov ,

When I sign the simplified invoice using the official SDK command, the reporting API responds successfully with a status of Reported. However, when I sign the same invoice manually by following the steps outlined in the SigningProcessUpdated.pdf document, the reporting API returns a 400 Bad Request with below error.

i have tested both cases in sandbox environment.

{
“type”: “ERROR”,
“code”: “signed-properties-hashing”,
“category”: “CERTIFICATE_ERRORS”,
“message”: “Invalid signed properties hashing, SignedProperties with id=‘xadesSignedProperties’”,
“status”: “ERROR”
}

Dear @Biplab1 , unfortunately I cannot help you here. It seems you have some mistake in your signing process. We ourselves are using self-written python SDK and do not have any issues now. It took us a lot of time to fix all the issues in signing, onboarding, applying workarounds etc…

It seems you have to go this journey as well, guys. Or you should reach for official ZATCA support to help you.

Best regards, Sergei

Dear @sergei.shishov ,

Thanks for your quick response.

@sergei.shishov
can you please share your csr generation code?
Im facing issue for b2c compliance check while onboarding.
My code:

 def generate_csr(self):
        private_key = self.generate_private_key()
        
        # Build the CSR
        csr_builder = x509.CertificateSigningRequestBuilder()
        csr_builder = csr_builder.subject_name(x509.Name([
            x509.NameAttribute(NameOID.COMMON_NAME, self.config.get('csr.common.name', '')),
            x509.NameAttribute(NameOID.ORGANIZATION_NAME, self.config.get('csr.organization.name', '')),
            x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, self.config.get('csr.organization.unit.name', '')),
            x509.NameAttribute(NameOID.COUNTRY_NAME, self.config.get('csr.country.name', 'SA')),
        ]))

        # Add ASN.1 extension
        csr_builder = csr_builder.add_extension(
            x509.UnrecognizedExtension(
                ObjectIdentifier("1.3.6.1.4.1.311.20.2"), 
                UTF8String(self.asn_template).dump()
            ),
            critical=False
        )
        #print("\nVAT:\n"+ self.config.get('csr.organization.identifier', ''))
        
        # Add SAN extension
        csr_builder = csr_builder.add_extension(
            x509.SubjectAlternativeName([
                x509.DirectoryName(x509.Name([
                    x509.NameAttribute(ObjectIdentifier("2.5.4.4"), self.config.get('csr.serial.number', '')),
                    x509.NameAttribute(ObjectIdentifier("0.9.2342.19200300.100.1.1"), self.config.get('csr.organization.identifier', '')),
                    x509.NameAttribute(ObjectIdentifier("2.5.4.12"), self.config.get('csr.invoice.type', '')),
                    x509.NameAttribute(ObjectIdentifier("2.5.4.26"), self.config.get('csr.location.address', '')),
                    x509.NameAttribute(ObjectIdentifier("2.5.4.15"), self.config.get('csr.industry.business.category', ''))
                ]))
            ]),
            critical=False
        )

        # Sign the CSR with the private key
        csr = csr_builder.sign(private_key, hashes.SHA256(), default_backend())

        # Serialize private key and CSR
        private_key_pem = private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption()
        )
        csr_pem = csr.public_bytes(serialization.Encoding.PEM)

        # Strip header/footer from private key
        private_key_content = re.sub(
            r'-----BEGIN .* PRIVATE KEY-----|-----END .* PRIVATE KEY-----|\n', '', 
            private_key_pem.decode('utf-8')
        )

        

        # Encode CSR in Base64
        csr_base64 = base64.b64encode(csr_pem).decode('utf-8')

        return private_key_content, csr_base64