Chilkat HOME .NET Core C# Android™ AutoIt C C# C++ Chilkat2-Python CkPython Classic ASP DataFlex Delphi ActiveX Delphi DLL Go Java Lianja Mono C# Node.js Objective-C PHP ActiveX PHP Extension Perl PowerBuilder PowerShell PureBasic Ruby SQL Server Swift 2 Swift 3,4,5... Tcl Unicode C Unicode C++ VB.NET VBScript Visual Basic 6.0 Visual FoxPro Xojo Plugin
(Node.js) Verify Multiple Signatures in XMLDemonstrates how to verify multiple signatures within a single XML document.
var os = require('os'); if (os.platform() == 'win32') { if (os.arch() == 'ia32') { var chilkat = require('@chilkat/ck-node21-win-ia32'); } else { var chilkat = require('@chilkat/ck-node21-win64'); } } else if (os.platform() == 'linux') { if (os.arch() == 'arm') { var chilkat = require('@chilkat/ck-node21-arm'); } else if (os.arch() == 'x86') { var chilkat = require('@chilkat/ck-node21-linux32'); } else { var chilkat = require('@chilkat/ck-node21-linux64'); } } else if (os.platform() == 'darwin') { if (os.arch() == 'arm64') { var chilkat = require('@chilkat/ck-node21-mac-m1'); } else { var chilkat = require('@chilkat/ck-node21-macosx'); } } function chilkatExample() { // This example requires the Chilkat API to have been previously unlocked. // See Global Unlock Sample for sample code. // A sample XML file containing multiple signatures is available at: // https://www.chilkatsoft.com/exampleData/document.signed.bes.cs.xml var http = new chilkat.Http(); var sbXml = new chilkat.StringBuilder(); var success = http.QuickGetSb("https://www.chilkatsoft.com/exampleData/document.signed.bes.cs.xml",sbXml); if (success !== true) { console.log(http.LastErrorText); return; } // Load the XML containing the signature to be verified. var verifier = new chilkat.XmlDSig(); success = verifier.LoadSignatureSb(sbXml); if (success !== true) { console.log(verifier.LastErrorText); return; } // How many Signatures exist in this XML? console.log("Number of XML signatures = " + verifier.NumSignatures); // Let's show the XML nicely indented, so we can make sense of it. // Loading the XML into an XML parser and re-emitting with nice formatting // changes whitespace that breaks the signatures. We're only doing this // for the example to examine this XML, which contains 2 ds:Signature's // and each signature has multiple references. // This is what we have: // (scroll down to continue with this example..) // <?xml version="1.0" encoding="UTF-8" ?> // <collection Id="root"> // <album> // <title>Questions, unanswered</title> // <artist>Steve and the flubberblubs</artist> // <year>1989</year> // <t:tracks xmlns:t="http://test.xades4j/tracks"> // <t:song length="4:05" tracknumber="1"> // <t:title>What do you know?</t:title> // <t:artist>Steve and the flubberblubs</t:artist> // <t:lastplayed>2006-10-17-08:31</t:lastplayed> // </t:song> // <t:song length="3:45" tracknumber="2"> // <t:title>Who do you know?</t:title> // <t:artist>Steve and the flubberblubs</t:artist> // <t:lastplayed>2006-10-17-08:35</t:lastplayed> // </t:song> // <t:song length="5:14" tracknumber="3"> // <t:title>When do you know?</t:title> // <t:artist>Steve and the flubberblubs</t:artist> // <t:lastplayed>2006-10-17-08:39</t:lastplayed> // </t:song> // <t:song length="4:19" tracknumber="4"> // <t:title>Do you know?</t:title> // <t:artist>Steve and the flubberblubs</t:artist> // <t:lastplayed>2006-10-17-08:44</t:lastplayed> // </t:song> // </t:tracks> // </album> // <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="xmldsig-ff7d9ad7-f36d-4af0-b21a-7db2e840efad"> // <ds:SignedInfo> // <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /> // <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /> // <ds:Reference Id="xmldsig-ff7d9ad7-f36d-4af0-b21a-7db2e840efad-ref0" URI="#root"> // <ds:Transforms> // <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> // </ds:Transforms> // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> // <ds:DigestValue>rD/g8soqKz8EiPUBhEWfcQacS0ta4ULHX3dKMEH6ZoQ=</ds:DigestValue> // </ds:Reference> // <ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#xmldsig-ff7d9ad7-f36d-4af0-b21a-7db2e840efad-signedprops"> // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> // <ds:DigestValue>pfrrRjkGNPiRF2Bjuj3IJTGSEFYc2PDs6FCNAUJOu8E=</ds:DigestValue> // </ds:Reference> // </ds:SignedInfo> // <ds:SignatureValue Id="xmldsig-ff7d9ad7-f36d-4af0-b21a-7db2e840efad-sigvalue">Vb/2ay4rX9cytiRCmBkgRkE4d0E05nkM412CwOHvTagCXPZZ2B2ifbmrQznTEU6Jz0dF65j5kU7C // bYK+9fMKB0lmqx2kUdWeBa30Rl/3ELKWKOLeDFN91zC3q4a6dtzQGwBidWex+2dO8Z69sBd2aTS6 // S6nyGs53kTspDHfBeyg=</ds:SignatureValue> // <ds:KeyInfo> // <ds:X509Data> // <ds:X509Certificate>MIICbTCCAdqgAwIBAgIQpkK0uals+ItHxBlpJuypOTAJBgUrDgMCHQUAMD8xCzAJBgNVBAYTAlBU // MQ0wCwYDVQQKEwRJU0VMMQswCQYDVQQLEwJDQzEUMBIGA1UEAxMLSXRlcm1lZGlhdGUwHhcNMTAw // NjI1MTc1ODQ5WhcNMzkxMjMxMjM1OTU5WjBCMQswCQYDVQQGEwJQVDENMAsGA1UEChMESVNFTDEL // MAkGA1UECxMCQ0MxFzAVBgNVBAMTDkx1aXMgR29uY2FsdmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GN // ADCBiQKBgQCpP9acMX69Dbg9ciMLFc5dm1tlpTY9OTNZ/EaCYoGVhh/3+DFgyIbEer6SA24hpREm // AhNG9+Ca0AurDPPgb3aKWFY9pj1WcOctis0VsR0YvzqP+2IGFqKDCd7bXFvv2tI0dEvpdc0oO6PF // Q02xvJG0kxQf44XljOCjUBU43jkJawIDAQABo28wbTBrBgNVHQEEZDBigBBdbbL4pDKLT56PpOpA // /56toTwwOjELMAkGA1UEBhMCUFQxDTALBgNVBAoTBElTRUwxCzAJBgNVBAsTAkNDMQ8wDQYDVQQD // EwZUZXN0Q0GCEN00x9qe7SuWQvpLK0/oay8wCQYFKw4DAh0FAAOBgQBSma8g9dQjiQo4WUljRRuG // yMUVRyCqW/9oRz8+0EoLNR/AhrIlGqdNbqQ1BkncgNNdqMAus5VD34v/EhgrkgWN5fZajMpYsmcR // Ahu4PzJ6hggAlWWMy245JwIYuV0s1Oi39GVTxVNOBIX//AONZlGWO4S2Psb1mqdZ99b/MugsaA==</ds:X509Certificate> // </ds:X509Data> // </ds:KeyInfo> // <ds:Object> // <xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" Target="#xmldsig-ff7d9ad7-f36d-4af0-b21a-7db2e840efad"> // <xades:SignedProperties Id="xmldsig-ff7d9ad7-f36d-4af0-b21a-7db2e840efad-signedprops"> // <xades:SignedSignatureProperties> // <xades:SigningCertificate> // <xades:Cert> // <xades:CertDigest> // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> // <ds:DigestValue>4btVb5gQ5cdcNhGpvDSWQZabPQrR9jf1x8e3YF9Ajss=</ds:DigestValue> // </xades:CertDigest> // <xades:IssuerSerial> // <ds:X509IssuerName>CN=Itermediate,OU=CC,O=ISEL,C=PT</ds:X509IssuerName> // <ds:X509SerialNumber>-119284162484605703133798696662099777223</ds:X509SerialNumber> // </xades:IssuerSerial> // </xades:Cert> // <xades:Cert> // <xades:CertDigest> // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> // <ds:DigestValue>vm5QpbblsWV7fCYXotPhNTeCt4nk8cLFuF36L5RJ4Ok=</ds:DigestValue> // </xades:CertDigest> // <xades:IssuerSerial> // <ds:X509IssuerName>CN=TestCA,OU=CC,O=ISEL,C=PT</ds:X509IssuerName> // <ds:X509SerialNumber>-46248926895392336918291885380930606289</ds:X509SerialNumber> // </xades:IssuerSerial> // </xades:Cert> // <xades:Cert> // <xades:CertDigest> // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> // <ds:DigestValue>AUaN+IdhKQqxIVmEOrFwq+Dn22ebTkXJqD3BoOP/x8E=</ds:DigestValue> // </xades:CertDigest> // <xades:IssuerSerial> // <ds:X509IssuerName>CN=TestCA,OU=CC,O=ISEL,C=PT</ds:X509IssuerName> // <ds:X509SerialNumber>-99704378678639105802976522062798066869</ds:X509SerialNumber> // </xades:IssuerSerial> // </xades:Cert> // </xades:SigningCertificate> // <xades:SignerRole> // <xades:ClaimedRoles> // <xades:ClaimedRole>CounterSignature maniac</xades:ClaimedRole> // </xades:ClaimedRoles> // </xades:SignerRole> // </xades:SignedSignatureProperties> // </xades:SignedProperties> // <xades:UnsignedProperties> // <xades:UnsignedSignatureProperties> // <xades:CounterSignature> // <ds:Signature Id="xmldsig-7479045c-8083-49eb-9043-1ac2af4a759c" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> // <ds:SignedInfo> // <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /> // <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /> // <ds:Reference Id="xmldsig-7479045c-8083-49eb-9043-1ac2af4a759c-ref0" URI="#xmldsig-ff7d9ad7-f36d-4af0-b21a-7db2e840efad-sigvalue"> // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> // <ds:DigestValue>Nr5JKCScyqjKWneJw2AC6YmdU/2JZA5Pj40fkVCFbL4=</ds:DigestValue> // </ds:Reference> // <ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#xmldsig-7479045c-8083-49eb-9043-1ac2af4a759c-signedprops"> // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> // <ds:DigestValue>PJWDlPFdx4TJ5AXT3nIbFa2euboYGM7bpuBmol4nKSQ=</ds:DigestValue> // </ds:Reference> // </ds:SignedInfo> // <ds:SignatureValue Id="xmldsig-7479045c-8083-49eb-9043-1ac2af4a759c-sigvalue">MCcli4l5rAsGeJX2gOmoYDIAXnbszmRwOH94y7kHnpxCwGwoVrCaLSONtgKEy8mj9Ehqa/R5Dj5g // DgC77VkNIaRKD613JMnbsaqZ7PD0iVivLvBkasTch4PX92UEbk8EvCgzxvhlgN+L6zSLsv65sFcR // lFUGluMtzrqlDKvts38=</ds:SignatureValue> // <ds:KeyInfo> // <ds:X509Data> // <ds:X509Certificate>MIICbTCCAdqgAwIBAgIQpkK0uals+ItHxBlpJuypOTAJBgUrDgMCHQUAMD8xCzAJBgNVBAYTAlBU // MQ0wCwYDVQQKEwRJU0VMMQswCQYDVQQLEwJDQzEUMBIGA1UEAxMLSXRlcm1lZGlhdGUwHhcNMTAw // NjI1MTc1ODQ5WhcNMzkxMjMxMjM1OTU5WjBCMQswCQYDVQQGEwJQVDENMAsGA1UEChMESVNFTDEL // MAkGA1UECxMCQ0MxFzAVBgNVBAMTDkx1aXMgR29uY2FsdmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GN // ADCBiQKBgQCpP9acMX69Dbg9ciMLFc5dm1tlpTY9OTNZ/EaCYoGVhh/3+DFgyIbEer6SA24hpREm // AhNG9+Ca0AurDPPgb3aKWFY9pj1WcOctis0VsR0YvzqP+2IGFqKDCd7bXFvv2tI0dEvpdc0oO6PF // Q02xvJG0kxQf44XljOCjUBU43jkJawIDAQABo28wbTBrBgNVHQEEZDBigBBdbbL4pDKLT56PpOpA // /56toTwwOjELMAkGA1UEBhMCUFQxDTALBgNVBAoTBElTRUwxCzAJBgNVBAsTAkNDMQ8wDQYDVQQD // EwZUZXN0Q0GCEN00x9qe7SuWQvpLK0/oay8wCQYFKw4DAh0FAAOBgQBSma8g9dQjiQo4WUljRRuG // yMUVRyCqW/9oRz8+0EoLNR/AhrIlGqdNbqQ1BkncgNNdqMAus5VD34v/EhgrkgWN5fZajMpYsmcR // Ahu4PzJ6hggAlWWMy245JwIYuV0s1Oi39GVTxVNOBIX//AONZlGWO4S2Psb1mqdZ99b/MugsaA==</ds:X509Certificate> // </ds:X509Data> // </ds:KeyInfo> // <ds:Object> // <xades:QualifyingProperties Target="#xmldsig-7479045c-8083-49eb-9043-1ac2af4a759c" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#"> // <xades:SignedProperties Id="xmldsig-7479045c-8083-49eb-9043-1ac2af4a759c-signedprops"> // <xades:SignedSignatureProperties> // <xades:SigningTime>2012-10-13T14:26:18.783+01:00</xades:SigningTime> // <xades:SigningCertificate> // <xades:Cert> // <xades:CertDigest> // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> // <ds:DigestValue>4btVb5gQ5cdcNhGpvDSWQZabPQrR9jf1x8e3YF9Ajss=</ds:DigestValue> // </xades:CertDigest> // <xades:IssuerSerial> // <ds:X509IssuerName>CN=Itermediate,OU=CC,O=ISEL,C=PT</ds:X509IssuerName> // <ds:X509SerialNumber>-119284162484605703133798696662099777223</ds:X509SerialNumber> // </xades:IssuerSerial> // </xades:Cert> // <xades:Cert> // <xades:CertDigest> // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> // <ds:DigestValue>vm5QpbblsWV7fCYXotPhNTeCt4nk8cLFuF36L5RJ4Ok=</ds:DigestValue> // </xades:CertDigest> // <xades:IssuerSerial> // <ds:X509IssuerName>CN=TestCA,OU=CC,O=ISEL,C=PT</ds:X509IssuerName> // <ds:X509SerialNumber>-46248926895392336918291885380930606289</ds:X509SerialNumber> // </xades:IssuerSerial> // </xades:Cert> // <xades:Cert> // <xades:CertDigest> // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> // <ds:DigestValue>AUaN+IdhKQqxIVmEOrFwq+Dn22ebTkXJqD3BoOP/x8E=</ds:DigestValue> // </xades:CertDigest> // <xades:IssuerSerial> // <ds:X509IssuerName>CN=TestCA,OU=CC,O=ISEL,C=PT</ds:X509IssuerName> // <ds:X509SerialNumber>-99704378678639105802976522062798066869</ds:X509SerialNumber> // </xades:IssuerSerial> // </xades:Cert> // </xades:SigningCertificate> // </xades:SignedSignatureProperties> // </xades:SignedProperties> // </xades:QualifyingProperties> // </ds:Object> // </ds:Signature> // </xades:CounterSignature> // </xades:UnsignedSignatureProperties> // </xades:UnsignedProperties> // </xades:QualifyingProperties> // </ds:Object> // </ds:Signature> // </collection> // // When I look at the complicated XML above, there are specific things I look at to get a handle // on the situation. // // 1) Does the signature already embed the public keys required for verification? // Within each <ds:Signature>, look for the <ds:KeyInfo>. In this case, I can see that // each signature contains the full X.509 certificate needed to verify (<ds:KeyInfo><ds:X509Data><ds:X509Certificate>). // This means that Chilkat will automatically use the public keys contained within the base64 certificates // already present in the signature. // // 2) Look at each <ds:Reference> within each <ds:Signature>. Do the URI attribute values begin with "#"? // If so, then these are same-document references, and there's no need to explicitly fetch external data for reference verification. // Chilkat can automatically validate each same-document Reference. // // So it turns out that this seemingly formidable XML document is easy to verify... // Here we go... var i = 0; while (i < verifier.NumSignatures) { // The Selector property is used to set our context to the Nth signature. // For example, if VerifySignature is called when Selector = 0, then the 1st signature is verified. // If VerifySignature is called when Selector = 1, then the 2nd signature is verified, and so on. verifier.Selector = i; var verifyReferenceDigests = true; // The quick way to validate all references and the signature over the SignedInfo // is to call VerifySignature with verifyReferenceDigests equal to true. var verified = verifier.VerifySignature(verifyReferenceDigests); console.log("Signature " + (i+1) + " and all reference digests verified = " + verified); // We can also get information about each signature. // For example, we could get information about each Reference... // The NumReferences property returns the number of references for the Signature indicated by the Selector property. var numReferences = verifier.NumReferences; console.log(" number of references: " + numReferences); var j = 0; while (j < numReferences) { // Get information about the Jth reference in the Ith signature. console.log(" reference " + j + ":"); // Is this a same-document or external reference? console.log(" is external: " + verifier.IsReferenceExternal(j)); // For external references, the URI could be used by an application to fetch the referenced data... console.log(" uri: " + verifier.ReferenceUri(j)); j = j+1; } // We could also get the KeyInfo for each Signature, which might be needed if we need to // load and set a public key that is not physically present within the KeyInfo already. // keyInfoXml: Xml var keyInfoXml = verifier.GetKeyInfo(); console.log(" key info: " + keyInfoXml.GetXml()); i = i+1; } // Here's the output of this example: // Number of XML signatures = 2 // Signature 1 and all reference digests verified = True // number of references: 2 // reference 0: // is external: False // uri: #root // reference 1: // is external: False // uri: #xmldsig-ff7d9ad7-f36d-4af0-b21a-7db2e840efad-signedprops // key info: // <ds:KeyInfo> // <ds:X509Data> // <ds:X509Certificate> // MIICbTCCAdqgAwIBAgIQpkK0uals+ItHxBlpJuypOTAJBgUrDgMCHQUAMD8xCzAJBgNVBAYTAlBU // MQ0wCwYDVQQKEwRJU0VMMQswCQYDVQQLEwJDQzEUMBIGA1UEAxMLSXRlcm1lZGlhdGUwHhcNMTAw // NjI1MTc1ODQ5WhcNMzkxMjMxMjM1OTU5WjBCMQswCQYDVQQGEwJQVDENMAsGA1UEChMESVNFTDEL // MAkGA1UECxMCQ0MxFzAVBgNVBAMTDkx1aXMgR29uY2FsdmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GN // ADCBiQKBgQCpP9acMX69Dbg9ciMLFc5dm1tlpTY9OTNZ/EaCYoGVhh/3+DFgyIbEer6SA24hpREm // AhNG9+Ca0AurDPPgb3aKWFY9pj1WcOctis0VsR0YvzqP+2IGFqKDCd7bXFvv2tI0dEvpdc0oO6PF // Q02xvJG0kxQf44XljOCjUBU43jkJawIDAQABo28wbTBrBgNVHQEEZDBigBBdbbL4pDKLT56PpOpA // /56toTwwOjELMAkGA1UEBhMCUFQxDTALBgNVBAoTBElTRUwxCzAJBgNVBAsTAkNDMQ8wDQYDVQQD // EwZUZXN0Q0GCEN00x9qe7SuWQvpLK0/oay8wCQYFKw4DAh0FAAOBgQBSma8g9dQjiQo4WUljRRuG // yMUVRyCqW/9oRz8+0EoLNR/AhrIlGqdNbqQ1BkncgNNdqMAus5VD34v/EhgrkgWN5fZajMpYsmcR // Ahu4PzJ6hggAlWWMy245JwIYuV0s1Oi39GVTxVNOBIX//AONZlGWO4S2Psb1mqdZ99b/MugsaA== // </ds:X509Certificate> // </ds:X509Data> // </ds:KeyInfo> // // Signature 2 and all reference digests verified = True // number of references: 2 // reference 0: // is external: False // uri: #xmldsig-ff7d9ad7-f36d-4af0-b21a-7db2e840efad-sigvalue // reference 1: // is external: False // uri: #xmldsig-7479045c-8083-49eb-9043-1ac2af4a759c-signedprops // key info: // <ds:KeyInfo> // <ds:X509Data> // <ds:X509Certificate> // MIICbTCCAdqgAwIBAgIQpkK0uals+ItHxBlpJuypOTAJBgUrDgMCHQUAMD8xCzAJBgNVBAYTAlBU // MQ0wCwYDVQQKEwRJU0VMMQswCQYDVQQLEwJDQzEUMBIGA1UEAxMLSXRlcm1lZGlhdGUwHhcNMTAw // NjI1MTc1ODQ5WhcNMzkxMjMxMjM1OTU5WjBCMQswCQYDVQQGEwJQVDENMAsGA1UEChMESVNFTDEL // MAkGA1UECxMCQ0MxFzAVBgNVBAMTDkx1aXMgR29uY2FsdmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GN // ADCBiQKBgQCpP9acMX69Dbg9ciMLFc5dm1tlpTY9OTNZ/EaCYoGVhh/3+DFgyIbEer6SA24hpREm // AhNG9+Ca0AurDPPgb3aKWFY9pj1WcOctis0VsR0YvzqP+2IGFqKDCd7bXFvv2tI0dEvpdc0oO6PF // Q02xvJG0kxQf44XljOCjUBU43jkJawIDAQABo28wbTBrBgNVHQEEZDBigBBdbbL4pDKLT56PpOpA // /56toTwwOjELMAkGA1UEBhMCUFQxDTALBgNVBAoTBElTRUwxCzAJBgNVBAsTAkNDMQ8wDQYDVQQD // EwZUZXN0Q0GCEN00x9qe7SuWQvpLK0/oay8wCQYFKw4DAh0FAAOBgQBSma8g9dQjiQo4WUljRRuG // yMUVRyCqW/9oRz8+0EoLNR/AhrIlGqdNbqQ1BkncgNNdqMAus5VD34v/EhgrkgWN5fZajMpYsmcR // Ahu4PzJ6hggAlWWMy245JwIYuV0s1Oi39GVTxVNOBIX//AONZlGWO4S2Psb1mqdZ99b/MugsaA== // </ds:X509Certificate> // </ds:X509Data> // </ds:KeyInfo> // // } chilkatExample(); |
© 2000-2024 Chilkat Software, Inc. All Rights Reserved.