Sample code for 30+ languages & platforms
Xbase++ Requires Chilkat v11.0.0+

IPS MX Signature - Digitally Sign MX Document

See more XML Digital Signatures Examples

Demonstrates how to digitally sign ISO 20022 SWIFT MX messages.

Chilkat Xbase++ Downloads

Xbase++
LOCAL nSuccess
LOCAL oXmlToSign
LOCAL oGen
LOCAL oObject1
LOCAL oCert
LOCAL oSbXml
LOCAL oVerifier
LOCAL oVerifyCert
LOCAL oPubKey
LOCAL nNumSigs
LOCAL nVerifyIdx
LOCAL nVerified

nSuccess := 0

//  This example assumes the Chilkat API to have been previously unlocked.
//  See Global Unlock Sample for sample code.

nSuccess := 1

//  First create the XML to be signed, or load it from a file, or a string,

//  To load XML from a file:
oXmlToSign := CreateObject("Chilkat.Xml")
nSuccess := oXmlToSign:LoadXmlFile("c:/someDir/mx_document.xml")

//  Or to load XML from a string
nSuccess := oXmlToSign:LoadXml("...")

//  Or create the XML directly.
oXmlToSign:Clear()

//  Use this online tool to generate code from sample XML: 
//  Generate Code to Create XML

oXmlToSign:Tag := "DataPDU"
oXmlToSign:AddAttribute("xmlns", "urn:cma:stp:xsd:stp.1.0")
oXmlToSign:UpdateAttrAt("Body|AppHdr", 1, "xmlns", "urn:iso:std:iso:20022:tech:xsd:head.001.001.01")
oXmlToSign:UpdateChildContent("Body|AppHdr|Fr|FIId|FinInstnId|BICFI", "ZZZZZZZZ")
oXmlToSign:UpdateChildContent("Body|AppHdr|To|FIId|FinInstnId|BICFI", "YYYYYYYYYY")
oXmlToSign:UpdateChildContent("Body|AppHdr|BizMsgIdr", "ZZZZZZZZAXXX999999999999999999999")
oXmlToSign:UpdateChildContent("Body|AppHdr|MsgDefIdr", "pacs.008.001.08")
oXmlToSign:UpdateChildContent("Body|AppHdr|BizSvc", "IPS")
oXmlToSign:UpdateChildContent("Body|AppHdr|CreDt", "2017-09-13T18:18:00Z")
oXmlToSign:UpdateAttrAt("Body|Document", 1, "xmlns", "urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|GrpHdr|MsgId", "ZZZZZZZZAXXX999999999999999999999")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|GrpHdr|CreDtTm", "2017-09-13T18:18:00")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|GrpHdr|NbOfTxs", "1")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|GrpHdr|SttlmInf|SttlmMtd", "CLRG")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|PmtId|EndToEndId", "NOTPROVIDED")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|PmtId|TxId", "ZZZZZZZZAXXX999999999999999999999")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|PmtTpInf|ClrChanl", "RTNS")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|PmtTpInf|LclInstrm|Prtry", "CSCT")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|PmtTpInf|CtgyPurp|Prtry", "001")
oXmlToSign:UpdateAttrAt("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|IntrBkSttlmAmt", 1, "Ccy", "JOD")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|IntrBkSttlmAmt", "71.12")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|IntrBkSttlmDt", "2018-01-14")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|ChrgBr", "SLEV")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|InstgAgt|FinInstnId|BICFI", "ZZZZZZZZ")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|InstdAgt|FinInstnId|BICFI", "UBSIJOA0")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|Dbtr|Nm", "John Johnson")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|DbtrAcct|Id|IBAN", "JO22CITI00000000000555555555")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|DbtrAgt|FinInstnId|BICFI", "ZZZZZZZZ")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|DbtrAgt|FinInstnId|Othr|Id", "200004")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|DbtrAgt|FinInstnId|Othr|SchmeNm|Prtry", "1700099999")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|DbtrAgtAcct|Id|IBAN", "JO66CITI22222222222222222222")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|CdtrAgt|FinInstnId|BICFI", "UBSIJOA0")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|CdtrAgt|FinInstnId|Othr|Id", "210027")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|CdtrAgt|FinInstnId|Othr|SchmeNm|Prtry", "1400199999")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|CdtrAgtAcct|Id|IBAN", "JO44UBSI33333333333333333333")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|Cdtr|Nm", "Omega Jones")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|CdtrAcct|Id|IBAN", "JO95UBSI00000000000777777777")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|InstrForNxtAgt|InstrInf", "/BNF/Details")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|Purp|Prtry", "5814")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|RgltryRptg|Dtls|Inf", "SOMEINFORMATIONABOUTPAYMENT-1")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|RgltryRptg|Dtls|Inf[1]", "SOMEINFORMATIONABOUTPAYMENT-2")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|RgltryRptg|Dtls|Inf[2]", "SOMEINFORMATIONABOUTPAYMENT-3")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|Tax|Cdtr|TaxId", "9900083901")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|Tax|Dbtr|TaxId", "1000387561")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|RmtInf|Ustrd", "EDV UCUN ODENIR")
oXmlToSign:UpdateChildContent("Body|Document|FIToFICstmrCdtTrf|CdtTrfTxInf|RmtInf|Ustrd[1]", "EXTRA INFO")

//  The following XML is to be signed:

//  <?xml version="1.0" encoding="UTF-8"?>
//  <DataPDU xmlns="urn:cma:stp:xsd:stp.1.0">
//  	<Body>
//  		<AppHdr xmlns="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
//  			<Fr>
//  				<FIId>
//  					<FinInstnId>
//  						<BICFI>ZZZZZZZZ</BICFI>
//  					</FinInstnId>
//  				</FIId>
//  			</Fr>
//  			<To>
//  				<FIId>
//  					<FinInstnId>
//  						<BICFI>YYYYYYYYYY</BICFI>
//  					</FinInstnId>
//  				</FIId>
//  			</To>
//  			<BizMsgIdr>ZZZZZZZZAXXX999999999999999999999</BizMsgIdr>
//  			<MsgDefIdr>pacs.008.001.08</MsgDefIdr>
//  			<BizSvc>IPS</BizSvc>
//  			<CreDt>2017-09-13T18:18:00Z</CreDt>
//  		</AppHdr>
//  		<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08">
//  			<FIToFICstmrCdtTrf>
//  				<GrpHdr>
//  					<MsgId>ZZZZZZZZAXXX999999999999999999999</MsgId>
//  					<CreDtTm>2017-09-13T18:18:00</CreDtTm>
//  					<NbOfTxs>1</NbOfTxs>
//  					<SttlmInf>
//  						<SttlmMtd>CLRG</SttlmMtd>
//  					</SttlmInf>
//  				</GrpHdr>
//  				<CdtTrfTxInf>
//  					<PmtId>
//  						<EndToEndId>NOTPROVIDED</EndToEndId>
//  						<TxId>ZZZZZZZZAXXX999999999999999999999</TxId>
//  					</PmtId>
//  					<PmtTpInf>
//  						<ClrChanl>RTNS</ClrChanl>
//  						<LclInstrm>
//  							<Prtry>CSCT</Prtry>
//  						</LclInstrm>
//  						<CtgyPurp>
//  							<Prtry>001</Prtry>
//  						</CtgyPurp>
//  					</PmtTpInf>
//  					<IntrBkSttlmAmt Ccy="JOD">71.12</IntrBkSttlmAmt>
//  					<IntrBkSttlmDt>2018-01-14</IntrBkSttlmDt>
//  					<ChrgBr>SLEV</ChrgBr>
//  					<InstgAgt>
//  						<FinInstnId>
//  							<BICFI>ZZZZZZZZ</BICFI>
//  						</FinInstnId>
//  					</InstgAgt>
//  					<InstdAgt>
//  						<FinInstnId>
//  							<BICFI>UBSIJOA0</BICFI>
//  						</FinInstnId>
//  					</InstdAgt>
//  					<Dbtr>
//  						<Nm>John Johnson</Nm>
//  					</Dbtr>
//  					<DbtrAcct>
//  						<Id>
//  							<IBAN>JO22CITI00000000000555555555</IBAN>
//  						</Id>
//  					</DbtrAcct>
//  					<DbtrAgt>
//  						<FinInstnId>
//  							<BICFI>ZZZZZZZZ</BICFI>
//  							<Othr>
//  								<Id>200004</Id>
//  								<SchmeNm>
//  									<Prtry>1700089999</Prtry>
//  								</SchmeNm>
//  							</Othr>
//  						</FinInstnId>
//  					</DbtrAgt>
//  					<DbtrAgtAcct>
//  						<Id>
//  							<IBAN>JO66CITI22222222222222222222</IBAN>
//  						</Id>
//  					</DbtrAgtAcct>
//  					<CdtrAgt>
//  						<FinInstnId>
//  							<BICFI>UBSIJOA0</BICFI>
//  							<Othr>
//  								<Id>210027</Id>
//  								<SchmeNm>
//  									<Prtry>1400199999</Prtry>
//  								</SchmeNm>
//  							</Othr>
//  						</FinInstnId>
//  					</CdtrAgt>
//  					<CdtrAgtAcct>
//  						<Id>
//  							<IBAN>JO44UBSI33333333333333333333</IBAN>
//  						</Id>
//  					</CdtrAgtAcct>
//  					<Cdtr>
//  						<Nm>Omega Jones</Nm>
//  					</Cdtr>
//  					<CdtrAcct>
//  						<Id>
//  							<IBAN>JO95UBSI00000000000777777777</IBAN>
//  						</Id>
//  					</CdtrAcct>
//  					<InstrForNxtAgt>
//  						<InstrInf>/BNF/Details</InstrInf>
//  					</InstrForNxtAgt>
//  					<Purp>
//  						<Prtry>5814</Prtry>
//  					</Purp>
//  					<RgltryRptg>
//  						<Dtls>
//  							<Inf>SOMEINFORMATIONABOUTPAYMENT-1</Inf>
//  							<Inf>SOMEINFORMATIONABOUTPAYMENT-2</Inf>
//  							<Inf>SOMEINFORMATIONABOUTPAYMENT-3</Inf>
//  						</Dtls>
//  					</RgltryRptg>
//  					<Tax>
//  						<Cdtr>
//  							<TaxId>9900083901</TaxId>
//  						</Cdtr>
//  						<Dbtr>
//  							<TaxId>1000387561</TaxId>
//  						</Dbtr>
//  					</Tax>
//  					<RmtInf>
//  						<Ustrd>EDV UCUN ODENIR</Ustrd>
//  						<Ustrd>EXTRA INFO</Ustrd>
//  					</RmtInf>
//  				</CdtTrfTxInf>
//  			</FIToFICstmrCdtTrf>
//  		</Document>
//  	</Body>
//  </DataPDU>

oGen := CreateObject("Chilkat.XmlDSigGen")

oGen:SigLocation := "DataPDU|Body|AppHdr|Sgntr"
oGen:SigLocationMod := 0
oGen:SigNamespacePrefix := "ds"
oGen:SigNamespaceUri := "http://www.w3.org/2000/09/xmldsig#"
oGen:SignedInfoCanonAlg := "EXCL_C14N"
oGen:SignedInfoDigestMethod := "sha256"

//  Set the KeyInfoId before adding references..
oGen:KeyInfoId := "_f9f2c543-e50a-4a50-bd91-50155d27f7e2"

//  Create an Object to be added to the Signature.
oObject1 := CreateObject("Chilkat.Xml")
oObject1:Tag := "xades:QualifyingProperties"
oObject1:AddAttribute("xmlns:xades", "http://uri.etsi.org/01903/v1.3.2#")
oObject1:UpdateAttrAt("xades:SignedProperties", 1, "Id", "_4ed8e0ed-f47c-4262-909b-0458532ce7aa-signedprops")
oObject1:UpdateChildContent("xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningTime", "TO BE GENERATED BY CHILKAT")

oGen:AddObject("", oObject1:GetXml(), "", "")

//  -------- Reference 1 --------
oGen:AddSameDocRef("_f9f2c543-e50a-4a50-bd91-50155d27f7e2", "sha256", "EXCL_C14N", "", "")

//  -------- Reference 2 --------
oGen:AddObjectRef("_4ed8e0ed-f47c-4262-909b-0458532ce7aa-signedprops", "sha256", "EXCL_C14N", "", "http://uri.etsi.org/01903/v1.3.2#SignedProperties")

//  -------- Reference 3 --------
oGen:AddSameDocRef("", "sha256", "EXCL_C14N", "", "")

//  Provide a certificate + private key. (PFX password is test123)
oCert := CreateObject("Chilkat.Cert")
nSuccess := oCert:LoadPfxFile("qa_data/pfx/cert_test123.pfx", "test123")
IF (nSuccess == 0)
    ? oCert:LastErrorText
    oXmlToSign:destroy()
    oGen:destroy()
    oObject1:destroy()
    oCert:destroy()
    RETURN
ENDIF

oGen:SetX509Cert(oCert, 1)

oGen:KeyInfoType := "X509Data"
oGen:X509Type := "IssuerSerial"

//  Load XML to be signed...
oSbXml := CreateObject("Chilkat.StringBuilder")
oXmlToSign:GetXmlSb(oSbXml)

//  Can alternatively use "CompactSignedXml"
oGen:Behaviors := "IndentedSignature,LocalSigningTime"

//  Sign the XML...
nSuccess := oGen:CreateXmlDSigSb(oSbXml)
IF (nSuccess == 0)
    ? oGen:LastErrorText
    oXmlToSign:destroy()
    oGen:destroy()
    oObject1:destroy()
    oCert:destroy()
    oSbXml:destroy()
    RETURN
ENDIF

//  -----------------------------------------------

//  Save the signed XML to a file.
nSuccess := oSbXml:WriteFile("qa_output/mx_signed.xml", "utf-8", 0)

? oSbXml:GetAsString()

//  ----------------------------------------
//  Verify the signatures we just produced...
oVerifier := CreateObject("Chilkat.XmlDSig")
nSuccess := oVerifier:LoadSignatureSb(oSbXml)
IF (nSuccess == 0)
    ? oVerifier:LastErrorText
    oXmlToSign:destroy()
    oGen:destroy()
    oObject1:destroy()
    oCert:destroy()
    oSbXml:destroy()
    oVerifier:destroy()
    RETURN
ENDIF

//  Important: The above signature did not include the full X.509 certificate.
//  You must call verifier.SetPublicKey to provide the public key of the certificate required for validation.

oVerifyCert := CreateObject("Chilkat.Cert")
nSuccess := oVerifyCert:LoadFromFile("qa_data/certs/cert_test123.cer")
IF (nSuccess == 0)
    ? oVerifyCert:LastErrorText
    oXmlToSign:destroy()
    oGen:destroy()
    oObject1:destroy()
    oCert:destroy()
    oSbXml:destroy()
    oVerifier:destroy()
    oVerifyCert:destroy()
    RETURN
ENDIF

oPubKey := CreateObject("Chilkat.PublicKey")
oVerifyCert:GetPublicKey(oPubKey)

oVerifier:SetPublicKey(oPubKey)

nNumSigs := oVerifier:NumSignatures
nVerifyIdx := 0
DO WHILE nVerifyIdx < nNumSigs
    oVerifier:Selector := nVerifyIdx
    nVerified := oVerifier:VerifySignature(1)
    IF (nVerified != 1)
        ? oVerifier:LastErrorText
        oXmlToSign:destroy()
        oGen:destroy()
        oObject1:destroy()
        oCert:destroy()
        oSbXml:destroy()
        oVerifier:destroy()
        oVerifyCert:destroy()
        oPubKey:destroy()
        RETURN
    ENDIF

    nVerifyIdx := nVerifyIdx + 1
ENDDO
? "All signatures were successfully verified."

oXmlToSign:destroy()
oGen:destroy()
oObject1:destroy()
oCert:destroy()
oSbXml:destroy()
oVerifier:destroy()
oVerifyCert:destroy()
oPubKey:destroy()