/* $Id: TestFirmaSat.cpp $
* Last updated:
* $Date: 2021-09-08 06:51:00 $
* $Version: 10.0.0 $
*/
/******************************* LICENSE ***********************************
* Copyright (C) 2021 David Ireland, DI Management Services Pty Limited.
* All rights reserved. <www.di-mgt.com.au> <www.cryptosys.net>
* The code in this module is licensed under the terms of the MIT license.
* For a copy, see <http://opensource.org/licenses/MIT>
****************************************************************************
*/
#include <iostream>
#include <fstream>
#include <clocale>
#include <string>
#include <cctype>
#include <assert.h>
#include "firmasat.hpp"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h> // For ``SetConsoleOutputCP(CP_UTF8);``
#endif
using std::cout;
using std::endl;
/* Case-insensitive string comparison */
static bool iequals(std::string &str1, std::string &str2)
{
return ((str1.size() == str2.size()) && std::equal(str1.begin(), str1.end(), str2.begin(), [](char & c1, char & c2){
return (c1 == c2 || std::toupper(c1) == std::toupper(c2));
}));
}
/* Return length of file in bytes or -1 if error */
static long long file_length(const std::string &fileName)
{
std::ifstream file(fileName.c_str(), std::ifstream::in | std::ifstream::binary);
if (!file.is_open()) {
return -1;
}
file.seekg(0, std::ios::end);
long long len = file.tellg();
file.close();
return len;
}
static std::string file_read_to_string(const std::string &fileName)
{
std::ifstream in(fileName);
std::string contents((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
return contents;
}
int main()
{
// Set up console and locale for UTF-8 characters
std::setlocale(LC_ALL, "en_US.utf8");
#ifdef _WIN32
// Set console display page to UTF-8
SetConsoleOutputCP(CP_UTF8);
#endif
cout << "__cplusplus=" << __cplusplus << endl;
cout << "INTERROGATE THE CORE diFirmaSAT2 DLL:" << endl;
cout << "Gen::Version=" << firmasat::Gen::Version() << endl;
cout << "Gen::ModuleName=" << firmasat::Gen::ModuleName() << endl;
cout << "Gen::Platform=" << firmasat::Gen::Platform() << endl;
cout << "Gen::CompileTime=" << firmasat::Gen::CompileTime() << endl;
cout << "Gen::LicenceType=" << firmasat::Gen::LicenceType() << endl;
cout << "Gen::Comments=" << firmasat::Gen::Comments() << endl;
std::string s, fname, newname, outfile, keyfile, password, certfile;
std::string s1, newpassword, xmlstring, newxmlstring;
std::string digest, digest1;
std::string attr, attr1;
std::string elementName, attributeName, query;
std::string certfiledata, keyfiledata;
int n;
//*************
// DO THE TESTS
//*************
try { // Overall try to catch any errors at all.
cout << endl << "FORM THE PIPESTRING FROM AN XML FILE:" << endl;
fname = "cfdv33a-base.xml";
s = firmasat::Sat::MakePipeStringFromXml(fname);
cout << "Sat::MakePipeStringFromXml('" << fname << "')=" << s << endl;
cout << endl << "SIGN AN XML FILE:" << endl;
fname = "cfdv33a-base.xml";
newname = "cfdv33a_new-signed.xml";
keyfile = "emisor.key";
password = "12345678a"; /* CAUTION: DO NOT HARD-CODE REAL PASSWORDS! */
certfile = "emisor.cer";
n = firmasat::Sat::SignXml(newname, fname, keyfile, password, certfile);
cout << "Sat::SignXml('" << fname << "'-->'" << newname << "') returns " << n << " (0=>success)" << endl;
// Did we make a valid XML file?
n = firmasat::Sat::VerifySignature(newname);
cout << "Sat::VerifySignature('" << newname << "') returns " << n << " (0=>success)" << endl;
cout << endl << "VERIFY A SIGNATURE IN AN XML FILE:" << endl;
cout << "1. One we know is good:" << endl;
fname = "cfdv33a-signed-tfd.xml";
s = firmasat::Sat::VerifySignature(fname);
cout << "Sat::VerifySignature('" << fname << "') returns " << n << " (0=>success)" << endl;
cout << "2. One we just made, so it should be good:" << endl;
fname = newname;
s = firmasat::Sat::VerifySignature(fname);
cout << "Sat::VerifySignature('" << fname << "') returns " << n << " (0=>success)" << endl;
cout << endl << "FORM THE DIGEST OF THE PIPESTRING IN AN XML FILE:" << endl;
fname = "cfdv33a-base.xml";
digest = firmasat::Sat::MakeDigestFromXml(fname);
cout << "Sat::MakeDigestFromXml('" << fname << "')=" << digest << endl;
cout << endl << "EXTRACT THE DIGEST FROM THE SIGNATURE IN AN XML FILE:" << endl;
fname = "cfdv33a-signed-tfd.xml";
digest1 = firmasat::Sat::ExtractDigestFromSignature(fname);
cout << "Sat::ExtractDigestFromSignature('" << fname << "')=" << digest1 << endl;
/* check that the two digests match (caution: upper- vs lower-case) */
assert(iequals(digest, digest1));
cout << "\nEXPECTING ERRORS..." << endl;
try {
s = firmasat::Sat::MakeDigestFromXml("missing.file");
cout << "MakeDigestFromXml=[" << s << "]" << endl;
}
catch (std::exception& e) {
cout << e.what() << endl;
}
try {
s = firmasat::Sat::MakeDigestFromXml("emisor.key"); // Not an XML file
cout << "MakeDigestFromXml=[" << s << "]" << endl;
}
catch (std::exception& e) {
cout << e.what() << endl;
}
// Test default Error Message after a successful method call...
n = firmasat::Gen::Version();
cout << "Default ErrorMessage=[" << firmasat::Err::FormatErrorMessage() << "]" << endl;
cout << "...END ERRORS" << endl << endl;
cout << endl << "VALIDATE THE STRUCTURE OF XML FILES:" << endl;
cout << "1. A valid one:" << endl;
fname = "cfdv33a-signed-tfd.xml";
n = firmasat::Sat::ValidateXml(fname);
cout << "Sat::ValidateXml('" << fname << "') returns " << n << " (0=>success)" << endl;
cout << "2. An invalid one (missing version):" << endl;
fname = "cfdv33a-bad-nover.xml";
n = firmasat::Sat::ValidateXml(fname);
cout << "Sat::ValidateXml('" << fname << "') returns " << n << " (0=>success)" << endl;
cout << "Err::LastError=[" << firmasat::Err::LastError() << "]" << endl;
cout << "3. Not complying with SAT spec:" << endl;
fname = "cfdv33a-badspec.xml";
n = firmasat::Sat::ValidateXml(fname);
cout << "Sat::ValidateXml('" << fname << "') returns " << n << " (0=>success)" << endl;
cout << "Err::LastError=[" << firmasat::Err::LastError() << "]" << endl;
cout << "4. Valid XML but invalid type:" << endl;
fname = "V3_2_BadCurp.xml";
n = firmasat::Sat::ValidateXml(fname);
cout << "Sat::ValidateXml('" << fname << "') returns " << n << " (0=>success)" << endl;
cout << "Err::LastError=[" << firmasat::Err::LastError() << "]" << endl;
n = firmasat::Sat::ValidateXml(fname, firmasat::Sat::XmlOption::Loose);
cout << "Sat::ValidateXml('" << fname << "', Loose) returns " << n << " (0=>success)" << endl;
cout << endl << "EXTRACT AN ATTRIBUTE FROM AN XML FILE:" << endl;
fname = "cfdv33a-signed-tfd.xml";
elementName = "Comprobante";
attributeName = "Sello"; // NB Capital letter 'S'
s = firmasat::Sat::GetXmlAttribute(fname, attributeName, elementName);
cout << "Sat::GetXmlAttribute=" << s << endl;
cout << "ATTRIBUTE MISSING..." << endl;
attributeName = "missing";
s = firmasat::Sat::GetXmlAttribute(fname, attributeName, elementName);
cout << "Sat::GetXmlAttribute=" << s << endl;
if (firmasat::Sat::XmlNoMatch() == s) {
cout << "Matches XmlNoMatch()" << endl;
}
// XmlNoMatch tests...
cout << "Sat::XmlNoMatch=" << firmasat::Sat::XmlNoMatch() << endl;
if (firmasat::Sat::XmlNoMatch() == s) {
cout << " Match for firmasat::Sat::XmlNoMatch()" << endl;
}
firmasat::Sat::SetXmlNoMatch("##No coinciden##");
cout << "Sat::XmlNoMatch=" << firmasat::Sat::XmlNoMatch() << endl;
s = firmasat::Sat::GetXmlAttribute(fname, attributeName, elementName);
cout << "Sat::GetXmlAttribute=" << s << endl;
// Set as default
firmasat::Sat::SetXmlNoMatch();
cout << "Sat::XmlNoMatch(default)=" << firmasat::Sat::XmlNoMatch() << endl;
cout << "EXTRACT AN ATTRIBUTE WITH ACCENTED CHARACTERS:" << endl;
fname = "cfdv33a-base.xml";
elementName = "cfdi:Emisor";
attributeName = "Nombre";
s = firmasat::Sat::GetXmlAttribute(fname, attributeName, elementName);
cout << "Sat::GetXmlAttribute=" << s << endl;
cout << "EXTRACT AN ATTRIBUTE WITH ACCENTED CHARACTERS IN ITS NAME:" << endl;
fname = "cfdv33a-nomina12.xml";
elementName = "nomina12:CompensacionSaldosAFavor";
attributeName = "Año"; // Hardcoded enye: 'A' + U+00F1 LATIN SMALL LETTER N WITH TILDE + 'o'
s = firmasat::Sat::GetXmlAttribute(fname, attributeName, elementName);
cout << "Sat::GetXmlAttribute=" << s << endl;
cout << "EXTRACT AN ATTRIBUTE VALUE WHICH IS EMPTY:" << endl;
s = firmasat::Sat::GetXmlAttribute("<a e=''></a>", "e", "a");
cout << "Sat::GetXmlAttribute='" << s << "'" << endl;
cout << "\nATTEMPT TO EXTRACT AN ATTRIBUTE VALUE FROM INVALID DATA..." << endl;
try {
s = firmasat::Sat::GetXmlAttribute("missing.file", "e", "a");
cout << "GetXmlAttribute=[" << s << "]" << endl;
}
catch (std::exception& e) {
cout << e.what() << endl;
}
try {
s = firmasat::Sat::GetXmlAttribute("<a badxml>", "e", "a");
cout << "GetXmlAttribute=[" << s << "]" << endl;
}
catch (std::exception& e) {
cout << e.what() << endl;
}
cout << "\nQUERY X.509 CERTIFICATE:" << endl;
cout << "1. From embedded `certificado` in XML" << endl;
fname = "cfdv33a-signed-tfd.xml";
cout << "FILE: " << fname << endl;
query = "serialNumber";
s = firmasat::Sat::QueryCert(fname, query);
cout << "Sat::QueryCert(" << query << ")=[" << s << "]" << endl;
query = "rfc";
s = firmasat::Sat::QueryCert(fname, query);
cout << "Sat::QueryCert(" << query << ")=[" << s << "]" << endl;
query = "organizationName";
s = firmasat::Sat::QueryCert(fname, query);
cout << "Sat::QueryCert(" << query << ")=[" << s << "]" << endl;
cout << "2. From X.509 file" << endl;
fname = "pac.cer";
cout << "FILE: " << fname << endl;
query = "serialNumber";
s = firmasat::Sat::QueryCert(fname, query);
cout << "Sat::QueryCert(" << query << ")=[" << s << "]" << endl;
query = "rfc";
s = firmasat::Sat::QueryCert(fname, query);
cout << "Sat::QueryCert(" << query << ")=[" << s << "]" << endl;
query = "organizationName";
s = firmasat::Sat::QueryCert(fname, query);
cout << "Sat::QueryCert(" << query << ")=[" << s << "]" << endl;
cout << "\nGET CERTIFICATE AS A BASE64 STRING:" << endl;
fname = "emisor.cer";
cout << "FILE: " << fname << endl;
s = firmasat::Sat::GetCertAsString(fname);
cout << "Sat::GetCertAsString:" << endl << s << endl;
// Compare against string from XML file
fname = "cfdv33a-signed-tfd.xml";
cout << "FILE: " << fname << endl;
s1 = firmasat::Sat::GetCertAsString(fname);
cout << "Sat::GetCertAsString:" << endl << s1 << endl;
// Make sure they match
assert(s == s1);
cout << "\nMAKE A SIGNATURE FROM A BASE XML FILE:" << endl;
fname = "cfdv33a-base.xml";
keyfile = "emisor.key";
password = "12345678a"; /* CAUTION: DO NOT HARD-CODE REAL PASSWORDS! */
s = firmasat::Sat::MakeSignatureFromXml(fname, keyfile, password);
cout << "Sat::MakeSignatureFromXml:" << endl << s << endl;
cout << "\nCHECK PRIVATE KEY MATCHES PUBLIC KEY IN CERTIFICATE:" << endl;
certfile = "emisor.cer";
keyfile = "emisor.key";
password = "12345678a"; /* CAUTION: DO NOT HARD-CODE REAL PASSWORDS! */
n = firmasat::Sat::CheckKeyAndCert(keyfile, password, certfile);
cout << "Sat::CheckKeyAndCert(" << keyfile << ", " << certfile << ") returns " << n << " (expected 0)" << endl;
assert(0 == n);
/* Get embedded certificate from XML doc */
certfile = "cfdv33a-signed-tfd.xml";
keyfile = "emisor.key";
n = firmasat::Sat::CheckKeyAndCert(keyfile, password, certfile);
cout << "Sat::CheckKeyAndCert(" << keyfile << ", " << certfile << ") returns " << n << " (expected 0)" << endl;
assert(0 == n);
cout << "Expecting errors..." << endl;
// Now do it wrong: note no exceptions, just a nonzero return value.
certfile = "pac.cer";
n = firmasat::Sat::CheckKeyAndCert(keyfile, password, certfile);
cout << "Sat::CheckKeyAndCert(" << keyfile << ", " << certfile << ") returns " << n << " (expected nonzero)" << endl;
assert(0 != n);
cout << " " << firmasat::Err::FormatErrorMessage(n) << endl;
certfile = "emisor.cer";
keyfile = "emisor.key";
password = "badpassword";
n = firmasat::Sat::CheckKeyAndCert(keyfile, password, certfile);
cout << "Sat::CheckKeyAndCert(" << keyfile << ", " << certfile << ", wrong-password) returns " << n << " (expected nonzero)" << endl;
assert(0 != n);
cout << " " << firmasat::Err::FormatErrorMessage(n) << endl;
cout << "\nGET RECEIPT (COMPROBANTE) VERSION NUMBER FROM XML FILE:" << endl;
fname = "cfdv33a-base.xml";
n = firmasat::Sat::XmlReceiptVersion(fname);
cout << "Sat::XmlReceiptVersion('" << fname << "')=" << n << endl;
assert(33 == n);
// One-liners used in documentation
cout << firmasat::Sat::XmlReceiptVersion("cfdv33a-base.xml") << endl; // 33
cout << firmasat::Sat::XmlReceiptVersion("ConVolE12345-base.xml") << endl; // 4011
cout << "\nCREATE CADENA ORIGINAL DEL TIMBRE FISCAL DIGITAL (PIPESTRING FOR TFD):" << endl;
fname = "cfdv33a-signed-tfd.xml";
s = firmasat::Tfd::MakePipeStringFromXml(fname);
cout << "Tfd::MakePipeStringFromXml('" << fname << "')=" << endl << s << endl;
cout << "\nFORM DIGEST OF PIPESTRING FOR TFD:" << endl;
fname = "cfdv33a-signed-tfd.xml";
digest = firmasat::Tfd::MakeDigestFromXml(fname);
cout << "Tfd::MakeDigestFromXml('" << fname << "')=" << endl << digest << endl;
cout << "\nEXTRACT DIGEST FROM TFD SELLOSAT:" << endl;
fname = "cfdv33a-signed-tfd.xml";
certfile = "pac.cer";
// NB certificate is required for TFD option
digest1 = firmasat::Tfd::ExtractDigestFromSignature(fname, certfile);
cout << "Tfd::ExtractDigestFromSignature('" << fname << ", " << certfile << "')=" << endl << digest1 << endl;
assert(iequals(digest, digest1));
cout << "\nPRETEND WE ARE A PAC WITH A KEY ALLOWED TO SIGN THE TFD:" << endl;
fname = "cfdv33a-signed-tfd.xml";
keyfile = "pac.key";
password = "12345678a"; /* CAUTION: DO NOT HARD-CODE REAL PASSWORDS! */
s = firmasat::Tfd::MakeSignatureFromXml(fname, keyfile, password);
cout << "Tfd::MakeSignatureFromXml('" << fname << ", " << keyfile << "')=" << endl << s << endl;
cout << "\nVERIFY SIGNATURE IN TFD SELLOSAT:" << endl;
fname = "cfdv33a-signed-tfd.xml";
certfile = "pac.cer";
n = firmasat::Tfd::VerifySignature(fname, certfile);
cout << "Tfd::VerifySignature('" << fname << ", " << certfile << "')=" << n << " (expected 0)" << endl;
assert(n == 0);
cout << "\nADD A TFD ELEMENT TO A SIGNED CFDI DOCUMENT USING PAC KEY:" << endl;
fname = "cfdv33a-signed.xml";
newname = "cfdv33a_new-tfd.xml";
certfile = "pac.cer";
keyfile = "pac.key";
password = "12345678a";
n = firmasat::Tfd::AddSignedTfd(newname, fname, keyfile, password, certfile);
cout << "Tfd::AddSignedTfd('" << fname << "'-->'" << newname << "') returns " << n << " (expected 0)" << endl;
assert(n == 0);
// Did we make a valid XML file?
n = firmasat::Sat::ValidateXml(newname);
cout << "Sat::ValidateXml('" << newname << "') returns " << n << endl;
assert(n == 0);
// Does it have a valid selloSAT?
n = firmasat::Tfd::VerifySignature(newname, certfile);
cout << "Tfd::VerifySignature('" << newname << ", " << certfile << "')=" << n << " (expected 0)" << endl;
assert(n == 0);
cout << "\nADD UTF-8 BOM TO EXISTING FILE:" << endl;
fname = "cfdv33a-signed-nobom.xml";
newname = "cfdv33a_new-signed-with-BOM.xml";
n = firmasat::Sat::FixBOM(newname, fname);
cout << "Sat::FixBOM(" << fname << "->" << newname << ")=" << n << " (expected 0)" << endl;
assert(n == 0);
cout << "\nEXTRACT ATTRIBUTES FROM CONSECUTIVE ELEMENTS:" << endl;
fname = "ejemplo_v32-tfd2015.xml";
attributeName = "descripcion";
elementName = "cfdi:Concepto";
cout << "For file '" << fname << "'" << endl;
// Loop until NoMatch
for (int i = 1; i <= 100; i++) {
std::string eName = elementName + "[" + std::to_string(i) + "]";
s = firmasat::Sat::GetXmlAttribute(fname, attributeName, eName);
cout << "Sat::GetXmlAttribute(" << attributeName<< "," << eName << ")=" << s << endl;
if (s == firmasat::Sat::XmlNoMatch()) {
break;
}
}
cout << "\nVALIDATE XML WITH STRICT AND LOOSE OPTIONS:" << endl;
cout << "Default strict behaviour (badly formed CURP attribute):" << endl;
fname = "V3_2_BadCurp.xml";
n = firmasat::Sat::ValidateXml(fname);
cout << "Sat::ValidateXml('" << fname << "') returns " << n << " (expected -ve error)" << endl;
cout << firmasat::Err::FormatErrorMessage(n) << endl;
assert(n != 0);
cout << "Using XmlOption.Loose:" << endl;
n = firmasat::Sat::ValidateXml(fname, firmasat::Sat::XmlOption::Loose);
cout << "Sat::ValidateXml('" << fname << "', XmlOption.Loose) returns " << n << " (expected 0)" << endl;
assert(n == 0);
cout << "\nGET PRIVATE KEY AS BASE64:" << endl;
fname = "emisor.key";
password = "12345678a";
s = firmasat::Sat::GetKeyAsString(fname, password);
cout << "Sat::GetKeyAsString('" << fname<< "')=" << endl << s << endl;
s = firmasat::Sat::GetKeyAsString(fname, password, firmasat::Sat::KeyOption::EncryptedPEM);
cout << "Sat::GetKeyAsString('" << fname << "', EncryptedPEM)=" << endl << s << endl;
cout << "\nWRITE PFX FROM PRIVATE KEY AND CERT:" << endl;
newname = "archivo_new-pfx.txt";
certfile = "emisor.cer";
keyfile = "emisor.key";
password = "12345678a";
newpassword = "clavedesalida";
n = firmasat::Sat::WritePfxFile(newname, newpassword, keyfile, password, certfile);
cout << "Sat::WritePfxFile() returns " << n << " (expected 0)" << endl;
assert(n == 0);
cout << " Created new file '" << newname << "' of length " << file_length(newname) << " bytes" << endl;
cout << "\nSAVE KEYFILE WITH NEW PASSWORD..." << endl;
keyfile = "emisor.key";
password = "12345678a";
newname = "emisor_new.key";
newpassword = "password123";
n = firmasat::Sat::NewKeyFile(newname, newpassword, keyfile, password);
cout << "Sat::NewKeyFile() returns " << n << " (expected 0)" << endl;
assert(0 == n);
cout << " Created new file '" << newname << "' of length " << file_length(newname) << " bytes" << endl;
// And again but saving as a PEM file instead of binary
keyfile = "emisor.key";
password = "12345678a";
newname = "emisor_new.pem";
newpassword = "password123";
n = firmasat::Sat::NewKeyFile(newname, newpassword, keyfile, password, firmasat::Sat::KeyFormat::PEM);
cout << "Sat::NewKeyFile() returns " << n << " (expected 0)" << endl;
assert(0 == n);
cout << " Created new file '" << newname << "' of length " << file_length(newname) << " bytes" << endl;
cout << "\nASCIIFY AN XML DOC..." << endl;
fname = "cfdv33a-base.xml";
cout << "FILE: " << fname << endl;
s = firmasat::Sat::Asciify(fname);
cout << s << endl;
// XML with non-ascii chars in the tag or element _name_ (these cannot be asciified)
fname = "cfdv33a-nomina12B.xml";
cout << "FILE: " << fname << endl;
s = firmasat::Sat::Asciify(fname);
cout << s << endl;
cout << "\nCHECK MESSAGE DIGEST IS THE SAME FOR THE ORIGINAL FILE AND THE ASCIIFIED STRING..." << endl;
digest = firmasat::Sat::MakeDigestFromXml(fname);
cout << "Digest(file) =" << digest << endl;
digest1 = firmasat::Sat::MakeDigestFromXml(s);
cout << "Digest(string)=" << digest << endl;
assert(digest == digest1);
cout << "\nGENERATE 3 UUIDs:" << endl;
for (int i = 0; i < 3; i++) {
s = firmasat::Sat::Uuid();
cout << s << endl;
}
cout << "\nINSERT CERTIFICATE DETAILS INTO XML..." << endl;
fname = "cfdv33a-base-nocertnum.xml";
newname = "cfdv33a-base_new-pluscert.xml";
certfile = "emisor.cer";
n = firmasat::Sat::InsertCert(newname, fname, certfile);
cout << "Sat::InsertCert() returns " << n << " (expecting 0)" << endl;
assert(0 == n);
// Check noCertificado attribute just inserted
// Original should be empty
attr = firmasat::Sat::GetXmlAttribute(fname, "NoCertificado", "cfdi:Comprobante");
cout << "Old NoCertificado=[" << attr << "]" << endl;
attr1 = firmasat::Sat::GetXmlAttribute(newname, "NoCertificado", "cfdi:Comprobante");
cout << "New NoCertificado=[" << attr1 << "]" << endl;
cout << "\nINSERT CERTIFICATE DETAILS INTO XML AS STRING..." << endl;
s = firmasat::Sat::InsertCertToString(fname, certfile);
cout << "Sat::InsertCertToString() returns a string of length " << s.length() << endl;
assert(s.length() > 0);
attr1 = firmasat::Sat::GetXmlAttribute(s, "NoCertificado", "cfdi:Comprobante");
cout << "New NoCertificado=[" << attr1 << "]" << endl;
cout << "\nSIGN XML TO STRING:" << endl;
fname = "cfdv33a-base.xml";
// Read an XML file into a string
xmlstring = file_read_to_string(fname);
cout << "String from file '" << fname << "' has " << xmlstring.length() << " bytes" << endl;
/*
We can pass key file and certificate as "PEM" strings.
The "BEGIN/END" encapsulation is optional for a certificate,
but is required for the encrypted private key.
*/
certfiledata =
"-----BEGIN CERTIFICATE-----"
"MIIF+TCCA+GgAwIBAgIUMzAwMDEwMDAwMDAzMDAwMjM3MDgwDQYJKoZIhvcNAQELBQAwggFmMSAwHgY"
"DVQQDDBdBLkMuIDIgZGUgcHJ1ZWJhcyg0MDk2KTEvMC0GA1UECgwmU2VydmljaW8gZGUgQWRtaW5pc3"
"RyYWNpw7NuIFRyaWJ1dGFyaWExODA2BgNVBAsML0FkbWluaXN0cmFjacOzbiBkZSBTZWd1cmlkYWQgZ"
"GUgbGEgSW5mb3JtYWNpw7NuMSkwJwYJKoZIhvcNAQkBFhphc2lzbmV0QHBydWViYXMuc2F0LmdvYi5t"
"eDEmMCQGA1UECQwdQXYuIEhpZGFsZ28gNzcsIENvbC4gR3VlcnJlcm8xDjAMBgNVBBEMBTA2MzAwMQs"
"wCQYDVQQGEwJNWDEZMBcGA1UECAwQRGlzdHJpdG8gRmVkZXJhbDESMBAGA1UEBwwJQ295b2Fjw6FuMR"
"UwEwYDVQQtEwxTQVQ5NzA3MDFOTjMxITAfBgkqhkiG9w0BCQIMElJlc3BvbnNhYmxlOiBBQ0RNQTAeF"
"w0xNzA1MTgwMzU0NTZaFw0yMTA1MTgwMzU0NTZaMIHlMSkwJwYDVQQDEyBBQ0NFTSBTRVJWSUNJT1Mg"
"RU1QUkVTQVJJQUxFUyBTQzEpMCcGA1UEKRMgQUNDRU0gU0VSVklDSU9TIEVNUFJFU0FSSUFMRVMgU0M"
"xKTAnBgNVBAoTIEFDQ0VNIFNFUlZJQ0lPUyBFTVBSRVNBUklBTEVTIFNDMSUwIwYDVQQtExxBQUEwMT"
"AxMDFBQUEgLyBIRUdUNzYxMDAzNFMyMR4wHAYDVQQFExUgLyBIRUdUNzYxMDAzTURGUk5OMDkxGzAZB"
"gNVBAsUEkNTRDAxX0FBQTAxMDEwMUFBQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJdU"
"csHIEIgwivvAantGnYVIO3+7yTdD1tkKopbL+tKSjRFo1ErPdGJxP3gxT5O+ACIDQXN+HS9uMWDYnaU"
"RalSIF9COFCdh/OH2Pn+UmkN4culr2DanKztVIO8idXM6c9aHn5hOo7hDxXMC3uOuGV3FS4ObkxTV+9"
"NsvOAV2lMe27SHrSB0DhuLurUbZwXm+/r4dtz3b2uLgBc+Diy95PG+MIu7oNKM89aBNGcjTJw+9k+Wz"
"JiPd3ZpQgIedYBD+8QWxlYCgxhnta3k9ylgXKYXCYk0k0qauvBJ1jSRVf5BjjIUbOstaQp59nkgHh45"
"c9gnwJRV618NW0fMeDzuKR0CAwEAAaMdMBswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwDQYJKoZ"
"IhvcNAQELBQADggIBABKj0DCNL1lh44y+OcWFrT2icnKF7WySOVihx0oR+HPrWKBMXxo9KtrodnB1tg"
"Ix8f+Xjqyphhbw+juDSeDrb99PhC4+E6JeXOkdQcJt50Kyodl9URpCVWNWjUb3F/ypa8oTcff/eMftQ"
"ZT7MQ1Lqht+xm3QhVoxTIASce0jjsnBTGD2JQ4uT3oCem8bmoMXV/fk9aJ3v0+ZIL42MpY4POGUa/iT"
"aawklKRAL1Xj9IdIR06RK68RS6xrGk6jwbDTEKxJpmZ3SPLtlsmPUTO1kraTPIo9FCmU/zZkWGpd8ZE"
"AAFw+ZfI+bdXBfvdDwaM2iMGTQZTTEgU5KKTIvkAnHo9O45SqSJwqV9NLfPAxCo5eRR2OGibd9jhHe8"
"1zUsp5GdE1mZiSqJU82H3cu6BiE+D3YbZeZnjrNSxBgKTIf8w+KNYPM4aWnuUMl0mLgtOxTUXi9MKnU"
"ccq3GZLA7bx7Zn211yPRqEjSAqybUMVIOho6aqzkfc3WLZ6LnGU+hyHuZUfPwbnClb7oFFz1PlvGOpN"
"DsUb0qP42QCGBiTUseGugAzqOP6EYpVPC73gFourmdBQgfayaEvi3xjNanFkPlW1XEYNrYJB4yNjphF"
"rvWwTY86vL2o8gZN0Utmc5fnoBTfM9r2zVKmEi6FUeJ1iaDaVNv47te9iS1ai4V4vBY8r"
"-----END CERTIFICATE-----";
keyfiledata =
"-----BEGIN ENCRYPTED PRIVATE KEY-----"
"MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI5qDMtGWYa2wCAggA"
"MBQGCCqGSIb3DQMHBAhFAqj+c0f8JASCBMhNUpNUp57vMu8L3LHBKRBTFl0VE3oq"
"BIEKBHFYYz063iiS0Y3tPW3cplLTSqG25MdbIQcHCxwmPVYNdetHUjqjeR+TklWg"
"tnMbLqvdMmmRxAFuHXznHFIa4U+YNedhFm7sdR2DsGFijm3vIpUbvpILtpTrhog/"
"EHAvZXV6+F86cYc9+LUg3d0DRwJc+sWmk+2xOoXvOvvpnnQqfhQxkSknfITmc+HA"
"WgHbKLK2q6e2RixjpWn0sA9LslYD0ZDn5uhrce+QEfK97asraFfiteqXf2Ll8B54"
"Ku/er+O2JEu62vVDFumwMtZOuHKH4NbjOmMzKIwRTKp/1jp6OTGYSKIRiTDXnTET"
"JwgItHahf7UAoM/qnkJa17Ood4hiCYopMyCXdhyMDJoFhWRanQODaiocb7XpMm1S"
"EpTtHZeKgEVWSc/obYgSgs4iY497UR2MUVZQSCBdRXCgs5g1c31cCwAZ6r41KMoL"
"OBVLtRXoT0mc0D6ovlwYuJhqYvuwjdNkWJS7qwXuy8b2ux4t027NGUXmgtb9XQDm"
"8yJrdTtm0CktWPKe7i2tQtBC2tAjduGAlBrzY+whySRN8KUJQbYKhOBaLXgEPI93"
"wi/SKHJO13WvfqqjKqrqJwB3tvhjz5E1uDKmDFoivdS76uq+k/xpmF5OWBmypWNV"
"iw7kgvmH1OeTBKYkUHIL85skL6pdycGnTk3g0AmG9xtPYu6pdSqUv+N8QmTdmmdu"
"85fDEN0fk2t2BRPANsbIqxopVfj5qIwm+8TbZDdNj8OssxrC5sRy5yDBjV4J+x25"
"3yaILn7wgUR6Yj6GaHUUF4GISmFZ/PTbnVPDd424w6hGV8NKtUHXq5ms2kJXo6XG"
"iGqjbdePM53QhdSrxTM5Dt76RcAInky6w5s/7gvT/w7tdbVA/SPhp4xgaT8Crmjb"
"k3upcSqNI0HuROBxOs0gRRAWXScUZJ0Vd1V0F+C5cG2R1CtGTYeRmIAwLwcWf6Dj"
"Y1Q+TOe/W3eTatOo+gIozjYDCk5ZNfeQzq4p1ApN6+gzS8kNxtvKOYJogjV74RK/"
"Xl7u7oLv4SZT7Nl1YRpScW1ouIcNNTP0AC+j2OFZ3YueN8CcmvXbgSW8pYRooTxn"
"Ffo9sdOL624uwRyb2DwwLO0Vo3aBIEIf8sm9sqocXmwh9sxFPEbTXPCuMSao8Qjy"
"BOlsCem2589NVZs0h0ipGwdbatcjkgf+hzRoYBdlvHtKHJ8gL/A/Ap8z0+TK5NaV"
"WUA+zXOZRZ66NYfs18DEbJKjwOcnnsLcfAMYoSn697148sL4JBv8IOmM6QXfxCl/"
"0yU0d5/876L5jOL56lfH0eBk8s2nioAl3yRBl2wlihWi39sA0bsdHFKYEX+LqPBB"
"CAdxZAvXCCJcdEdxOXSgEiFAmW9+IXFT/WJeGcZ4OmCd3Qf0fxGqFXA/9hIUumWd"
"e6s0wN8LjXuFZQaMDaaVIGXKguP3OijsfBF0PYzI+L6CfUi2BLaYNJTlbQxbncmW"
"2PKeDiypgt3ZY1PKV66o5OAJEAkV3vf9cRwXE5T8GwZHA+wx2rWC98hkH15xfI9q"
"EsYulVdcXWzCF58HFQjUoDon0e/QMukS0eNgq9ipmoKAWKyy7+TQw7Xx3MmqkGlL"
"HGM="
"-----END ENCRYPTED PRIVATE KEY-----";
password = "12345678a";
// Check key and certificate are matched
n = firmasat::Sat::CheckKeyAndCert(keyfiledata, password, certfiledata);
cout << "Sat::CheckKeyAndCert(STRINGS) returns " << n << " (expecting 0)" << endl;
// Create a new string containing signed XML (UTF-8 encoded), all input passed in memory
newxmlstring = firmasat::Sat::SignXmlToString(xmlstring, keyfiledata, password, certfiledata);
cout << "Signed XML string has " << newxmlstring.length() << " bytes" << endl;
cout << "\nPASS XML STRING TO OTHER SAT FUNCTIONS:" << endl;
n = firmasat::Sat::ValidateXml(newxmlstring);
cout << "Sat::ValidateXml(STRING) returns " << n << " (expecting 0)" << endl;
assert(0 == n);
n = firmasat::Sat::VerifySignature(newxmlstring);
cout << "Sat::VerifySignature(STRING) returns " << n << " (expecting 0)" << endl;
assert(0 == n);
n = firmasat::Sat::XmlReceiptVersion(newxmlstring);
cout << "Sat::XmlReceiptVersion(STRING) returns " << n << " (expecting 33)" << endl;
assert(n > 0);
// ******************************************
// FINALLY, DISPLAY QUICK INFO ABOUT THE CORE DLL
cout << "\nFINALLY, DETAILS OF CORE NATIVE DLL..." << endl;
cout << "DLL Version=" << firmasat::Gen::Version() << " [" << firmasat::Gen::Platform() << "] Lic={"
<< firmasat::Gen::LicenceType() << "} Compiled=[" << firmasat::Gen::CompileTime() << "] " << endl;
cout << "[" << firmasat::Gen::ModuleName() << "]" << endl;
cout << endl << "ALL DONE." << endl;
}
catch (std::exception& e) {
cout << e.what() << endl;
cout << "TESTS FAILED TO COMPLETE!!" << endl;
}
}