SEO Title: Fixing IRBM DS322 Digest Error in Signed UBL XML Invoices #ds322 #irbxml
Focus Keyphrase: IRB DS322 error
Meta Description: Learn how to fix the IRBM DS322 digest mismatch error during e-invoice submission in Laravel. Solve C14N issues and sign your UBL Invoice element correctly.
🧾 What is DS322?
DS322 is a digest mismatch error from IRBM’s MyInvois API. It occurs when your submitted XML contains a <ds:DigestValue>
that doesn’t match the value IRBM computes on their side.
IRBM compares the SHA-256 digest of your canonicalized <Invoice>
element (after transforms) to the value inside your <ds:SignedInfo>
block. If they don’t match — you get DS322.
❓ Why does DS322 happen?
Here’s what causes it:
Cause | Explanation |
---|---|
❌ Wrong canonicalization | You didn’t use Exclusive C14N correctly on <Invoice> |
❌ Wrong node reference | You signed a child node (e.g. <InvoiceLine> ) instead of the full <Invoice> |
❌ Signature block placement | The signature is outside the expected structure or added before canonicalizing |
❌ Enveloped-signature transform missing | IRBM expects this to remove the signature during digesting |
❌ You removed required UBLExtensions | IRBM expects the <ext:UBLExtensions> to remain part of the digest |
🕒 When do you get this error?
You’ll receive DS322 immediately after submitting a signed UBL XML invoice to:
POST https://preprod-api.myinvois.hasil.gov.my/api/v1.0/invoices
Response example:
{
"errorCode": "DS322",
"message": "Digest mismatch",
"propertyPath": "Invoice.UBLExtensions.SignatureInformation.Signature"
}
👨💻 Who is affected?
This error hits:
- Developers using xmlseclibs or manual DOM signing in Laravel
- Integrators converting IRBM’s sample XMLs manually
- Teams copy-pasting signature logic from other UBL projects (like Peppol) without adjusting to IRBM rules
🌐 Where is the problem?
It lies in this block (inside <ds:SignedInfo>
):
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>[calculated-hash]</DigestValue>
</Reference>
The digest value here must match the canonicalized version of your <Invoice>
element (excluding the signature itself via the enveloped transform).
🛠 How to Fix DS322 in Laravel (Step-by-Step)
✅ 1. Use xmlseclibs
with proper transform
$objDSig = new \RobRichards\XMLSecLibs\XMLSecurityDSig();
$objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
// This signs the entire document (root node), minus the signature block
$objDSig->addReference(
$doc, // full DOMDocument
XMLSecurityDSig::SHA256,
['http://www.w3.org/2000/09/xmldsig#enveloped-signature'],
['uri' => '']
);
✅ 2. Sign the document after building the entire <Invoice>
Make sure all these are already inserted into the DOM before signing:
<ext:UBLExtensions>
with<ds:Signature>
placeholder- All
cbc:*
fields likeUBLVersionID
,InvoiceTypeCode
, etc. - Invoice lines, tax totals, monetary totals
$unsignedXml = $doc->saveXML(); // after everything is added
$signedXml = $signatureService->sign($unsignedXml); // do not sign partial DOM
✅ 3. Use Exclusive C14N for digesting
IRBM uses exclusive canonicalization, so your signature must use:
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
And internally:
$canonicalized = $doc->C14N(true, false);
$digest = base64_encode(hash('sha256', $canonicalized, true));
✅ 4. Keep UBLExtensions
inside the digest
This is critical: do not remove <ext:UBLExtensions>
before digesting. The signature block inside <ext:ExtensionContent>
will be removed by the enveloped-signature transform, but the container itself must remain.
✅ 5. Confirm reference URI is empty string
You must sign the root element:
<Reference URI="">
This means “sign the whole document (root element) after removing the signature node.”
🧪 Debug Tip: Log Your Digest Locally
In Laravel:
$canonical = $doc->C14N(true, false);
$digest = base64_encode(hash('sha256', $canonical, true));
Log::debug('Canonical digest for Invoice', ['digest' => $digest]);
Compare this to the <DigestValue>
inside your <SignedInfo>
block.
✅ Final Checklist to Fix DS322
✅ What to Check | ✅ Fix Strategy |
---|---|
Reference URI | Set to "" (empty string) |
Canonicalization method | Use http://www.w3.org/2001/10/xml-exc-c14n# |
Signature block location | Inside <ext:UBLExtensions> |
Signature timing | Sign after generating full XML structure |
Transforms in <Reference> | Add enveloped-signature |
<ext:UBLExtensions> included in digest | Yes — only <ds:Signature> is removed |
✅ Summary
DS322 = digest mismatch on the main Invoice element.
Fix it by:
- Using exclusive C14N
- Applying the enveloped-signature transform
- Signing the entire Invoice node (with UBLExtensions)
- Canonicalizing only after the full XML is assembled
Tags:
#IRBIntegration #DS322 #UBLSignature #XMLDigest #LaravelMyInvois #DigitalSigning