Technical Assistance: Persistent "Invalid-CSR" Error in ZATCA Simulation Environment - Project AndalusSystem

Dear Developer Team,

I am currently developing a SaaS solution for laundries using Django/Python. To ensure full compliance with ZATCA’s Phase 2 requirements, we have built a dedicated .NET 8.0 Security Bridge to handle X509 certificate generation and digital signing, as Python has certain limitations with custom OIDs and ASN.1 encoding.

We are consistently hitting a 400 Bad Request: Invalid-CSR error when attempting to obtain the Compliance CSID (CCSID) in the Simulation Environment. Despite following several recommendations from the Fatoora Developer Community regarding field order and spacing, the issue persists.

1. Our Technical Stack

  • Backend: Python 3.14 / Django.

  • Security Bridge: .NET 8.0 Web API (using System.Security.Cryptography).

  • Endpoint: https://gw-fatoora.zatca.gov.sa/e-invoicing/simulation/compliance

2. CSR Implementation Details

Our .NET bridge generates the CSR manually using AsnWriter to ensure strict DER encoding. Our current CSR structure includes:

  • Key Algorithm: ECDSA (curve: secp256k1) with SHA256.

  • Subject Field Order: We follow the SDK-mandated order: CNOOUC.

  • Subject Attributes: * CN: Prefixed with TST- followed by the UUID.

    • O: Organization Name.

    • OU: Unit Name.

    • C: “SA” (encoded as PrintableString).

    • SerialNumber: (2.5.4.5) containing the 1-TST|2-TST|3-UUID format.

    • OrganizationIdentifier: (2.5.4.26) containing the VAT number (encoded as PrintableString).

  • Certificate Extensions:

    • Template (1.3.6.1.4.1.311.20.2): Set to PREZATCA-Code-Signing (encoded as BMPString) to simulate the -sim parameter.

    • Subject Alternative Name (SAN): We include a DirectoryName containing: SN, UID (VAT), title (1100), registeredAddress, and businessCategory.

  • Formatting: We have implemented a strict .Trim() on all inputs and ensured no unnecessary spaces exist around the = signs or within the RDN sequence.

3. Test Data Used

  • VAT Number: 310122393500003 (Standard ZATCA Test VAT).

  • OTP: 123456.

  • Common Name Format: TST-886431145-310122393500003.

4. The Error Response

JSON

{
    "errorCode": "400",
    "errorCategory": "Invalid-CSR",
    "errorMessage": "The provided Certificate Signing Request (CSR) is invalid."
}

5. My Specific Questions

  1. Does the Simulation environment now require the SAN (Subject Alternative Name) to be encoded as a GeneralName of type otherName instead of directoryName?

  2. Is there a specific requirement for the Invoice Type (0100 vs 1100) within the CSR for SaaS providers who don’t have a direct TIN/Portal access yet?

  3. Are there any hidden characters or specific OIDs that the new Simulation engine (post-Sept 2025 update) expects which might differ from the standard SDK output?

I would highly appreciate any guidance or if you could take a quick look at a sample CSR generated by our system.

“MIICUDCCAfYCAQAwgcExHDAaBgNVBAMME1RTVC0zMTAxMjIzOTM1MDAwMDMxFDASBgNVBAoMC1hZWiBjb21wYW55MRQwEgYDVQQLDAtNYWluIEJyYW5jaDELMAkGA1UEBhMCU0ExOzA5BgNVBAUMMjEtVFNUfDItVFNUfDMtOThmOGMwZGMtYThiZi00MmRhLWFhNjUtZDczMWM2MTZlNzU5MRgwFgYDVQQaEw8zMTAxMjIzOTM1MDAwMDMxETAPBgNVBA8MCFNlcnZpY2VzMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEsXMs1zdOSrXGUoAT5fL5ZObskWhH2DKle7XYGdGwuIfeR2SvE3bnjpWdG4c6Di8ycYybBHqgmu/Xce9xJV5RSKCB1DCB0QYJKoZIhvcNAQkOMYHDMIHAMCQGCSsGAQQBgjcUAgQXExVQUkVaQVRDQS1Db2RlLVNpZ25pbmcwgZcGA1UdEQSBjzCBjAyBiVNOPTEtVFNUfDItVFNUfDMtOThmOGMwZGMtYThiZi00MmRhLWFhNjUtZDczMWM2MTZlNzU5LFVJRD0zMTAxMjIzOTM1MDAwMDMsdGl0bGU9MTEwMCxyZWdpc3RlcmVkQWRkcmVzcz1SUlJEMjkyOSxidXNpbmVzc0NhdGVnb3J5PVNlcnZpY2VzMAoGCCqGSM49BAMCA0gAMEUCIQDPG7ez21JzvZETXMfaJy2+mGopBpC3BdBIeQsV/qzfgQIgR2ZGWW4m3TgUc7LWdsjYX/GWq379rajxh1hX/+UaDhQ=”

Best Regards,