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:
CN→O→OU→C. -
Subject Attributes: *
CN: Prefixed withTST-followed by the UUID.-
O: Organization Name. -
OU: Unit Name. -
C: “SA” (encoded asPrintableString). -
SerialNumber: (2.5.4.5) containing the1-TST|2-TST|3-UUIDformat. -
OrganizationIdentifier: (2.5.4.26) containing the VAT number (encoded asPrintableString).
-
-
Certificate Extensions:
-
Template (1.3.6.1.4.1.311.20.2): Set to
PREZATCA-Code-Signing(encoded asBMPString) to simulate the-simparameter. -
Subject Alternative Name (SAN): We include a
DirectoryNamecontaining:SN,UID(VAT),title(1100),registeredAddress, andbusinessCategory.
-
-
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
-
Does the Simulation environment now require the SAN (Subject Alternative Name) to be encoded as a
GeneralNameof typeotherNameinstead ofdirectoryName? -
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? -
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,