Sample code for 30+ languages & platforms
Dart 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 Dart Downloads

Dart
import 'package:chilkat/chilkat.dart';

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

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

  // To load XML from a file:
  final xmlToSign = CkXml();
  xmlToSign.loadXmlFile('c:/someDir/mx_document.xml');

  // Or to load XML from a string
  xmlToSign.loadXml('...');

  // Or create the XML directly.
  xmlToSign.clear();

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

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

  final gen = CkXmlDSigGen();

  gen.sigLocation = 'DataPDU|Body|AppHdr|Sgntr';
  gen.sigLocationMod = 0;
  gen.sigNamespacePrefix = 'ds';
  gen.sigNamespaceUri = 'http://www.w3.org/2000/09/xmldsig#';
  gen.signedInfoCanonAlg = 'EXCL_C14N';
  gen.signedInfoDigestMethod = 'sha256';

  // Set the KeyInfoId before adding references..
  gen.keyInfoId = '_f9f2c543-e50a-4a50-bd91-50155d27f7e2';

  // Create an Object to be added to the Signature.
  final object1 = CkXml();
  object1.tag = 'xades:QualifyingProperties';
  object1.addAttribute('xmlns:xades', 'http://uri.etsi.org/01903/v1.3.2#');
  object1.updateAttrAt('xades:SignedProperties', true, 'Id', '_4ed8e0ed-f47c-4262-909b-0458532ce7aa-signedprops');
  object1.updateChildContent('xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningTime', 'TO BE GENERATED BY CHILKAT');

  gen.addObject('', object1.getXml(), '', '');

  // -------- Reference 1 --------
  gen.addSameDocRef('_f9f2c543-e50a-4a50-bd91-50155d27f7e2', 'sha256', 'EXCL_C14N', '', '');

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

  // -------- Reference 3 --------
  gen.addSameDocRef('', 'sha256', 'EXCL_C14N', '', '');

  // Provide a certificate + private key. (PFX password is test123)
  final cert = CkCert();
  try {
    cert.loadPfxFile('qa_data/pfx/cert_test123.pfx', 'test123');
  } on ChilkatException catch (e) {
    print(e.lastErrorText);
    return;
  }

  gen.setX509Cert(cert, true);

  gen.keyInfoType = 'X509Data';
  gen.x509Type = 'IssuerSerial';

  // Load XML to be signed...
  final sbXml = CkStringBuilder();
  xmlToSign.getXmlSb(sbXml);

  // Can alternatively use "CompactSignedXml"
  gen.behaviors = 'IndentedSignature,LocalSigningTime';

  // Sign the XML...
  try {
    gen.createXmlDSigSb(sbXml);
  } on ChilkatException catch (e) {
    print(e.lastErrorText);
    return;
  }

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

  // Save the signed XML to a file.
  sbXml.writeFile('qa_output/mx_signed.xml', 'utf-8', false);

  print(sbXml.getAsString());

  // ----------------------------------------
  // Verify the signatures we just produced...
  final verifier = CkXmlDSig();
  try {
    verifier.loadSignatureSb(sbXml);
  } on ChilkatException catch (e) {
    print(e.lastErrorText);
    return;
  }

  // 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.

  final verifyCert = CkCert();
  try {
    verifyCert.loadFromFile('qa_data/certs/cert_test123.cer');
  } on ChilkatException catch (e) {
    print(e.lastErrorText);
    return;
  }

  final pubKey = CkPublicKey();
  verifyCert.getPublicKey(pubKey);

  verifier.setPublicKey(pubKey);

  final numSigs = verifier.numSignatures;
  var verifyIdx = 0;
  while (verifyIdx < numSigs) {
    verifier.selector = verifyIdx;
    try {
      verifier.verifySignature(true);
    } on ChilkatException catch (e) {
      print(e.lastErrorText);
      return;
    }

    verifyIdx++;
  }

  print('All signatures were successfully verified.');
}