今日已更新 35 条资讯 | 累计 37284 条内容
关于我们

Why Your ZATCA Phase 2 Invoice Passes Compliance and Fails Reporting

Mousa Hammad 2026年08月07日 20:36 6 次阅读 来源:Dev.to

If you are integrating ZATCA Phase 2 (Saudi Arabia's Fatoora e-invoicing) and you have seen this: { "type" : "ERROR" , "code" : "signed-properties-hashing" , "category" : "CERTIFICATE_ERRORS" , "message" : "Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties'" } ...after your invoice sailed through /compliance/invoices , this post is for you. It is the single most confusing failure mode in the whole integration, and the fix is not what the error suggests. The trap: SignedProperties exists in two byte-shapes The XAdES SignedProperties block is referenced twice in your signed document: ds:Reference URI="#xadesSignedProperties" carries a digest of the block. The block itself is embedded inside ds:Object > xades:QualifyingProperties . The natural assumption is that both refer to the same bytes. They do not. The hashed shape carries namespace declarations and starts at column 0: <xades:SignedProperties xmlns:xades= "http://uri.etsi.org/01903/v1.3.2#" Id= "xadesSignedProperties" > <xades:SignedSignatureProperties> <xades:SigningTime> 2026-08-07T02:14:33 </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" /> The embedded shape carries no namespace declarations (they are inherited from ancestors) and its root element is indented to column 32 : <xades:SignedProperties Id= "xadesSignedProperties" > <xades:SignedSignatureProperties> Embed the hashed shape verbatim - the intuitive thing to do - and the gateway rejects with signed-properties-hashing , even though your indentation "looks right". The second half of the trap: the digest encoding The digest is not the raw SHA-256 bytes in base64. It is base64 of the hex string : const crypto = require ( ' crypto ' ); // hashedShape = the namespaced, column-0 variant above const propsDigest = Buffer . from ( crypto . createHash ( ' sha256 ' ). update ( Buffer .

本文内容来源于互联网,版权归原作者所有
查看原文