Objective:
Digitally sign a UBL XML invoice for Malaysia’s IRBM MyInvois using:
- Canonicalization (Exclusive C14N)
- SHA256 digest
- XAdES enveloped signature
.p12
certificate- Proper XML placement per IRBM rules
🔐 1. Load certificate & private key from config
Load PEM certificate
Load PEM private key
Load .p12 path and passphrase
If PEM or key is missing → throw exception
🧾 2. Main Signing Entry: signAndInject(xml)
Function signAndInject(xml):
issuerName = fixed IRBM issuer string
digestData = hashDocument(xml) // C14N + SHA256
certDigest = hashRawCert() // For SignedProperties
serialNum = extractCertSerial() // Decimal serial from PEM
base64Cert = extractCertDER() // base64-encoded cert
signingTime = now + 5s
signedPropsDigest = digestSignedProperties(certDigest, serialNum, issuerName, signingTime)
signatureValue = signDigest(raw minified XML without signature, using .p12 private key)
Build:
- <cac:Signature> chunk
- <UBLExtensions> with <ds:Signature> structure using all above values
Insert:
- <cac:Signature> before <cac:AccountingSupplierParty>
- <UBLExtensions> after <Invoice>
Minify XML (remove extra whitespace)
Return final signed XML
🧮 3. Hash Document Function
Function hashDocument(xml):
Load into DOMDocument
Apply Exclusive C14N to <Invoice>
SHA256 hash it (raw + base64)
Return digest and canonicalized XML
🔐 4. Sign Canonicalized Digest Using .p12
Function signDigest(rawXML):
Load .p12
Extract private key
openssl_sign(SHA256 hash of digest)
Return base64 signature
📜 5. Build SignedProperties Digest
Build <xades:SignedProperties> XML
Inject: certDigest, issuer, serial number, signingTime
Minify XML (no whitespace between tags)
SHA256 hash and return base64
🧱 6. Build ds:SignedInfo Block
Function buildSignedInfoXml():
Reference 1: full document (URI="")
- with XPath transforms to exclude UBLExtensions and Signature
- SHA256 digest
Reference 2: SignedProperties (URI="#id-xades-signed-props")
- SHA256 digest
CanonicalizationMethod: Exclusive C14N
SignatureMethod: RSA-SHA256
🧩 7. Final XML Assembly
Insert <cac:Signature> tag before supplier section
Insert full <UBLExtensions> after <Invoice>
Return minified, signed XML string
✅ Output
Fully signed, IRBM-compliant UBL XML with:
- cac:Signature
- XAdES-compliant ds:Signature
- SHA256-RSA signature based on canonicalized content
- Certificate metadata and signing properties