/* TestFirmaSat.c */ // Some tests using the FirmaSAT C/C++ interface. // This uses plain-old ANSI C. // Requires certain files to exist in the current working directory. /* **************************** COPYRIGHT NOTICE **************************** * Copyright (C) 2010-11 DI Management Services Pty Limited. * All rights reserved. <www.di-mgt.com.au> <www.cryptosys.net> * $Id: TestFirmaSat.c $ * Last updated: * $Date: 2011-12-29 11:12:00 $ * $Version: 5.0.0 $ ************************* END OF COPYRIGHT NOTICE ************************ */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "diFirmaSat2.h" #ifdef NDEBUG /* Make sure assertion testing is turned on */ #undef NDEBUG #endif #include <assert.h> /* Link to the DLL library */ #if _WIN64 #if _DEBUG #define MYLIBDIR "../x64/Debug/" #else #define MYLIBDIR "../x64/Release/" #endif #else #if _DEBUG #define MYLIBDIR "../Debug/" #else #define MYLIBDIR "../Release/" #endif #endif #pragma comment(lib, MYLIBDIR "diFirmaSat2.lib") void display_all_errors(void); static void disp_error(long nErrCode) { char msg[1024]; long nchars; printf("Error code %ld", nErrCode); nchars = SAT_ErrorLookup(msg, sizeof(msg)-1, nErrCode); if (nchars > 0) printf(": %s", msg); nchars = SAT_LastError(msg, sizeof(msg)-1); if (nchars > 0) printf(" : %s", msg); putchar('\n'); } int file_exists(const char *fname) { FILE *fp; fp = fopen(fname, "rb"); if (fp == NULL) return 0; fclose(fp); return 1; } int required_files_exist(void) // Check for required files in current working directory { const char *arrFiles[] = { "aaa010101aaa_CSD_01.cer", "aaa010101aaa_CSD_01.key", "aaa010101aaa_CSD_02.cer", "aaa010101aaa_CSD_02.key", "detallista_base2011.xml", "Muestra_v2_bad.xml", "Muestra_v2_base2011.xml", "Muestra_v2_signed2011.xml", "ejemplo_v3_base2011.xml", "ejemplo_v3_tfd.xml", "ejemplo_v3_noprefix.xml", "V2_2-base.xml", "V3_2-base.xml", "V3_2_BadCurp.xml", "Muestra_v22-base.xml", "ejemplo_v32-base.xml", NULL }; const char *fname; int i; for (i = 0, fname = arrFiles[i]; fname; fname = arrFiles[++i]) { if (!file_exists(fname)) { printf("**ERROR: File %s is missing.\n", fname); return 0; } } return 1; } /* DO THE BUSINESS... */ int main(void) { long ret, nchars, n; char ch; char *buf, *buf1; char *fname; char *newname, *keyfile, *password, *certfile; char *attributeName, *elementName; char digest[SAT_MAX_HASH_CHARS+1]; /* Digest hex length plus one. [NB changed in v2.1] */ char digest1[SAT_MAX_HASH_CHARS+1]; char numstr[21]; char cdate[64]; int i; char eName[64]; /* Check if all required files exist in the CWD */ if (!required_files_exist()) { printf("Required file cannot be found in current working directory.\n"); exit(1); } printf("INTERROGATE THE CORE diFirmaSAT2 DLL:\n"); ret = SAT_Version(); printf("Version=%ld\n", ret); if (ret < 400) { printf("Require FirmaSAT version 4.0 or greater.\n"); exit(1); } ch = (char)SAT_LicenceType(); printf("LicenceType=%c\n", ch); nchars = SAT_ModuleName(NULL, 0, 0); if (nchars > 0) { buf = malloc(nchars+1); nchars = SAT_ModuleName(buf, nchars, 0); printf("Module=%s\n", buf); free(buf); } assert(nchars > 0); /* Detect platform [new in v2.0.1] */ nchars = SAT_ModuleName(NULL, 0, SAT_GEN_PLATFORM); if (nchars > 0) { buf = malloc(nchars+1); nchars = SAT_ModuleName(buf, nchars, 64); printf("Platform=%s\n", buf); free(buf); } assert(nchars > 0); nchars = SAT_CompileTime(NULL, 0); if (nchars > 0) { buf = malloc(nchars+1); nchars = SAT_CompileTime(buf, nchars); printf("Compiled=%s\n", buf); free(buf); } assert(nchars > 0); printf("\nFORM THE PIPESTRING FROM AN XML FILE: \n"); fname = "Muestra_v2_signed2011.xml"; nchars = SAT_MakePipeStringFromXml(NULL, 0, fname, SAT_ENCODE_UTF8); printf("SAT_MakePipeStringFromXml(UTF8) returns %ld\n", nchars); if (nchars >= 0) { buf = malloc(nchars+1); nchars = SAT_MakePipeStringFromXml(buf, nchars, fname, SAT_ENCODE_UTF8); printf("%s\n", buf); printf("Actual length=%ld\n", nchars); free(buf); } else disp_error(nchars); assert(nchars > 0); printf("\nSIGN AN XML FILE: \n"); fname = "Muestra_v2_base2011.xml"; newname = "Muestra_v2_signed2011-new.xml"; keyfile = "aaa010101aaa_CSD_01.key"; password = "a0123456789"; /* CAUTION: DO NOT HARD-CODE REAL PASSWORDS! */ certfile = "aaa010101aaa_CSD_01.cer"; ret = SAT_SignXml(newname, fname, keyfile, password, certfile, 0); printf("Sat.SignXml('%s'-->'%s') returns %ld\n", fname, newname, ret); assert (ret == 0); // Did we make a valid XML file? ret = SAT_ValidateXml(newname, 0); printf("SAT_ValidateXml(%s) returns %ld (0=>success)\n", newname, ret); assert (ret == 0); printf("\nVERIFY A SIGNATURE IN AN XML FILE: \n"); printf("1. One we know is good:\n"); fname = "Muestra_v2_signed2011.xml"; ret = SAT_VerifySignature(fname, NULL, 0); printf("Sat.VerifySignature('%s') returns %ld\n", fname, ret); assert (ret == 0); printf("2. One we just made, so it should be good:\n"); fname = newname; ret = SAT_VerifySignature(fname, NULL, 0); printf("Sat.VerifySignature('%s') returns %ld\n", fname, ret); assert (ret == 0); printf("\nFORM THE DIGEST OF THE PIPESTRING IN AN XML FILE: \n"); fname = "Muestra_v2_signed2011.xml"; ret = SAT_MakeDigestFromXml(digest, sizeof(digest)-1, fname, 0); printf("SAT_MakeDigestFromXml returns %ld\n", ret); if (ret < 0) disp_error(ret); printf("Digest=%s\n", digest); assert (ret > 0); printf("\nEXTRACT THE DIGEST FROM THE SIGNATURE IN AN XML FILE: \n"); fname = "Muestra_v2_signed2011.xml"; ret = SAT_ExtractDigestFromSignature(digest1, sizeof(digest1)-1, fname, NULL, 0); printf("SAT_ExtractDigestFromSignature returns %ld\n", ret); if (ret < 0) disp_error(ret); printf("Digest=%s\n", digest1); assert (ret > 0); /* check that the two digests match (caution: upper- vs lower-case) */ assert (_stricmp(digest, digest1) == 0); printf("\nTRY VALIDATING XML FILES:\n"); printf("1. A valid one:\n"); fname = "Muestra_v2_signed2011.xml"; ret = SAT_ValidateXml(fname, 0); printf("SAT_ValidateXml(%s) returns %ld (0=>success)\n", fname, ret); assert (ret == 0); printf("2. An invalid one (missing version):\n"); fname = "Muestra_v2_bad.xml"; ret = SAT_ValidateXml(fname, 0); printf("SAT_ValidateXml(%s) returns %ld (expected error)\n", fname, ret); assert (ret < 0); disp_error(ret); printf("3. An invalid one (empty noCertificado):\n"); fname = "ejemplo_v32-base.xml"; ret = SAT_ValidateXml(fname, 0); printf("SAT_ValidateXml(%s) returns %ld (expected error)\n", fname, ret); assert (ret < 0); disp_error(ret); printf("\nEXTRACT AN ATTRIBUTE FROM AN XML FILE: \n"); fname = "Muestra_v2_signed2011.xml"; elementName = "Comprobante"; attributeName = "sello"; nchars = SAT_GetXmlAttribute(NULL, 0, fname, attributeName, elementName); if (nchars >= 0) { buf = malloc(nchars+1); nchars = SAT_GetXmlAttribute(buf, nchars, fname, attributeName, elementName); printf("SAT_GetXmlAttribute('%s','%s','%s')=\n%s\n", fname, attributeName, elementName, buf); free(buf); } else disp_error(nchars); assert(nchars > 0); printf("\nGET DETAILS OF X.509 CERTIFICATE:\n"); printf("1. From embedded `certificado` in XML\n"); fname = "Muestra_v2_signed2011.xml"; printf("Input file: %s\n", fname); ret = SAT_GetCertNumber(numstr, sizeof(numstr)-1, fname, 0); printf("SAT_GetCertNumber returns %ld\n", ret); if (ret < 0) disp_error(ret); printf("serialNumber=%s\n", numstr); ret = SAT_GetCertExpiry(numstr, sizeof(numstr)-1, fname, 0); printf("SAT_GetCertExpiry returns %ld\n", ret); if (ret < 0) disp_error(ret); printf("notAfter=%s\n", numstr); // [v3.0] added this... ret = SAT_GetCertExpiry(numstr, sizeof(numstr)-1, fname, SAT_DATE_NOTBEFORE); printf("SAT_GetCertExpiry(DATE_NOTBEFORE) returns %ld\n", ret); if (ret < 0) disp_error(ret); printf("notBefore=%s\n", numstr); printf("2. From X.509 file\n"); fname = "aaa010101aaa_CSD_01.cer"; printf("Input file: %s\n", fname); ret = SAT_GetCertNumber(numstr, sizeof(numstr)-1, fname, 0); printf("SAT_GetCertNumber returns %ld\n", ret); if (ret < 0) disp_error(ret); printf("serialNumber=%s\n", numstr); ret = SAT_GetCertExpiry(numstr, sizeof(numstr)-1, fname, 0); printf("SAT_GetCertExpiry returns %ld\n", ret); if (ret < 0) disp_error(ret); printf("notAfter=%s\n", numstr); // [v3.0] added this... ret = SAT_GetCertExpiry(numstr, sizeof(numstr)-1, fname, SAT_DATE_NOTBEFORE); printf("SAT_GetCertExpiry(DATE_NOTBEFORE) returns %ld\n", ret); if (ret < 0) disp_error(ret); printf("notBefore=%s\n", numstr); printf("\nGET CERTIFICATE AS A BASE64 STRING:\n"); fname = "aaa010101aaa_CSD_01.cer"; printf("For file %s...\n", fname); nchars = SAT_GetCertAsString(NULL, 0, fname, 0); printf("SAT_GetCertAsString(%s) returns %ld\n", fname, nchars); if (nchars < 0) disp_error(ret); assert(nchars > 0); if (nchars >= 0) { buf = malloc(nchars+1); nchars = SAT_GetCertAsString(buf, nchars, fname, 0); printf("%s\n", buf); printf("Actual length=%ld\n", nchars); //free(buf); // Keep string for later... } else disp_error(nchars); assert(nchars > 0); // Compare against string from XML file fname = "Muestra_v2_signed2011.xml"; printf("For file %s...\n", fname); nchars = SAT_GetCertAsString(NULL, 0, fname, 0); if (nchars < 0) disp_error(ret); assert(nchars > 0); if (nchars >= 0) { buf1 = malloc(nchars+1); nchars = SAT_GetCertAsString(buf1, nchars, fname, 0); printf("Length of cert string=%ld\n", nchars); } else disp_error(nchars); assert(nchars > 0); // Compare strings if (strcmp(buf, buf1) == 0) printf("OK, cert strings are equal.\n"); else printf("ERROR: cert strings do not match!\n"); assert(strcmp(buf, buf1) == 0); free(buf); free(buf1); printf("\nMAKE A SIGNATURE FROM A BASE XML FILE: \n"); fname = "Muestra_v2_base2011.xml"; keyfile = "aaa010101aaa_CSD_01.key"; password = "a0123456789"; /* CAUTION: DO NOT HARD-CODE REAL PASSWORDS! */ nchars = SAT_MakeSignatureFromXml(NULL, 0, fname, keyfile, password); if (nchars >= 0) { buf = malloc(nchars+1); nchars = SAT_MakeSignatureFromXml(buf, nchars, fname, keyfile, password); printf("SAT_MakeSignatureFromXml('%s','%s')=\n%s\n", fname, keyfile, buf); free(buf); } else disp_error(nchars); assert(nchars > 0); printf("\nSIGN A DETALLISTA XML FILE: \n"); fname = "detallista_base2011.xml"; newname = "detallista-new-signed.xml"; keyfile = "aaa010101aaa_CSD_01.key"; password = "a0123456789"; /* CAUTION: DO NOT HARD-CODE REAL PASSWORDS! */ certfile = "aaa010101aaa_CSD_01.cer"; ret = SAT_SignXml(newname, fname, keyfile, password, certfile, 0); printf("SAT_SignXml(%s) returns %ld (0=>success)\n", fname, ret); if (ret != 0) disp_error(ret); assert(0 == ret); // Did we make a valid XML file? fname = newname; ret = SAT_ValidateXml(fname, 0); printf("SAT_ValidateXml(%s) returns %ld (0=>success)\n", fname, ret); if (ret != 0) disp_error(ret); assert(0 == ret); // Is the signature valid? ret = SAT_VerifySignature(fname, NULL, 0); printf("SAT_VerifySignature(%s) returns %ld (0=>success)\n", fname, ret); if (ret != 0) disp_error(ret); assert(0 == ret); printf("\nEXTRACT AN ATTRIBUTE FROM A DETALLISTA XML FILE: \n"); fname = "detallista-new-signed.xml"; elementName = "detallista:detallista"; attributeName = "documentStructureVersion"; nchars = SAT_GetXmlAttribute(NULL, 0, fname, attributeName, elementName); if (nchars >= 0) { buf = malloc(nchars+1); nchars = SAT_GetXmlAttribute(buf, nchars, fname, attributeName, elementName); printf("SAT_GetXmlAttribute('%s','%s','%s')='%s'\n", fname, attributeName, elementName, buf); //free(buf); // Save string for later } else disp_error(nchars); assert(nchars > 0); // Check against the correct answer assert(strcmp(buf, "AMC8.1") == 0); free(buf); printf("\nSIGN CFDI VERSION 3.0 XML FILE: \n"); fname = "ejemplo_v3_base2011.xml"; newname = "ejemplo_v3_signed-new.xml"; keyfile = "aaa010101aaa_CSD_01.key"; password = "a0123456789"; /* CAUTION: DO NOT HARD-CODE REAL PASSWORDS! */ certfile = "aaa010101aaa_CSD_01.cer"; ret = SAT_SignXml(newname, fname, keyfile, password, certfile, 0); printf("SAT_SignXml('%s'-->'%s') returns %ld\n", fname, newname, ret); assert (ret == 0); // Did we make a valid XML file? ret = SAT_ValidateXml(newname, 0); printf("SAT_ValidateXml(%s) returns %ld (0=>success)\n", newname, ret); assert (ret == 0); printf("\nVERIFY SIGNATURE IN AN XML FILE: \n"); fname = "ejemplo_v3_signed-new.xml"; ret = SAT_VerifySignature(fname, NULL, 0); printf("SAT_VerifySignature('%s') returns %ld\n", fname, ret); assert (ret == 0); printf("\nEXTRACT THE DIGEST FROM THE SIGNATURE IN AN XML FILE: \n"); fname = "ejemplo_v3_signed-new.xml"; ret = SAT_ExtractDigestFromSignature(digest, sizeof(digest)-1, fname, NULL, 0); printf("SAT_ExtractDigestFromSignature returns %ld\n", ret); if (ret < 0) disp_error(ret); printf("Digest=%s\n", digest); assert (ret > 0); printf("\nFORM THE SHA-1 DIGEST OF THE PIPESTRING IN AN XML FILE: \n"); fname = "ejemplo_v3_signed-new.xml"; ret = SAT_MakeDigestFromXml(digest, sizeof(digest)-1, fname, SAT_HASH_SHA1); printf("SAT_MakeDigestFromXml(SHA1) returns %ld\n", ret); if (ret < 0) disp_error(ret); printf("Digest=%s\n", digest); assert (ret > 0); // [v3.0] NEW FUNCTIONS ADDED... printf("\nCHECK PRIVATE KEY MATCHES PUBLIC KEY IN CERTIFICATE: \n"); certfile = "aaa010101aaa_CSD_01.cer"; keyfile = "aaa010101aaa_CSD_01.key"; password = "a0123456789"; /* CAUTION: DO NOT HARD-CODE REAL PASSWORDS! */ ret = SAT_CheckKeyAndCert(keyfile, password, certfile, 0); printf("SAT_CheckKeyAndCert(%s,%s) returns %ld\n", keyfile, certfile, ret); if (ret != 0) disp_error(ret); assert(ret == 0); certfile = "aaa010101aaa_CSD_02.cer"; keyfile = "aaa010101aaa_CSD_02.key"; password = "a0123456789"; ret = SAT_CheckKeyAndCert(keyfile, password, certfile, 0); printf("SAT_CheckKeyAndCert(%s,%s) returns %ld\n", keyfile, certfile, ret); if (ret != 0) disp_error(ret); assert(ret == 0); /* Get embedded certificate from XML doc */ certfile = "Muestra_v2_signed2011.xml"; keyfile = "aaa010101aaa_CSD_01.key"; password = "a0123456789"; ret = SAT_CheckKeyAndCert(keyfile, password, certfile, 0); printf("SAT_CheckKeyAndCert(%s,%s) returns %ld\n", keyfile, certfile, ret); if (ret != 0) disp_error(ret); assert(ret == 0); /* 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. */ certfile = "-----BEGIN CERTIFICATE-----" "MIIE/TCCA+WgAwIBAgIUMzAwMDEwMDAwMDAxMDAwMDA4MDAwDQYJKoZIhvcNAQEF" "BQAwggFvMRgwFgYDVQQDDA9BLkMuIGRlIHBydWViYXMxLzAtBgNVBAoMJlNlcnZp" "Y2lvIGRlIEFkbWluaXN0cmFjacOzbiBUcmlidXRhcmlhMTgwNgYDVQQLDC9BZG1p" "bmlzdHJhY2nDs24gZGUgU2VndXJpZGFkIGRlIGxhIEluZm9ybWFjacOzbjEpMCcG" "CSqGSIb3DQEJARYaYXNpc25ldEBwcnVlYmFzLnNhdC5nb2IubXgxJjAkBgNVBAkM" "HUF2LiBIaWRhbGdvIDc3LCBDb2wuIEd1ZXJyZXJvMQ4wDAYDVQQRDAUwNjMwMDEL" "MAkGA1UEBhMCTVgxGTAXBgNVBAgMEERpc3RyaXRvIEZlZGVyYWwxEjAQBgNVBAcM" "CUNveW9hY8OhbjEVMBMGA1UELRMMU0FUOTcwNzAxTk4zMTIwMAYJKoZIhvcNAQkC" "DCNSZXNwb25zYWJsZTogSMOpY3RvciBPcm5lbGFzIEFyY2lnYTAeFw0xMDA3MzAx" "NjU4NDBaFw0xMjA3MjkxNjU4NDBaMIGWMRIwEAYDVQQDDAlNYXRyaXogU0ExEjAQ" "BgNVBCkMCU1hdHJpeiBTQTESMBAGA1UECgwJTWF0cml6IFNBMSUwIwYDVQQtExxB" "QUEwMTAxMDFBQUEgLyBBQUFBMDEwMTAxQUFBMR4wHAYDVQQFExUgLyBBQUFBMDEw" "MTAxSERGUlhYMDExETAPBgNVBAsMCFVuaWRhZCAxMIGfMA0GCSqGSIb3DQEBAQUA" "A4GNADCBiQKBgQDD0ltQNthUNUfzq0t1GpIyapjzOn1W5fGM5G/pQyMluCzP9YlV" "AgBjGgzwYp9Z0J9gadg3y2ZrYDwvv8b72goyRnhnv3bkjVRKlus6LDc00K7Jl23U" "YzNGlXn5+i0HxxuWonc2GYKFGsN4rFWKVy3Fnpv8Z2D7dNqsVyT5HapEqwIDAQAB" "o4HqMIHnMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgbAMB0GA1UdDgQWBBSYodSw" "Rczzj5H7mcO3+mAyXz+y0DAuBgNVHR8EJzAlMCOgIaAfhh1odHRwOi8vcGtpLnNh" "dC5nb2IubXgvc2F0LmNybDAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0" "dHA6Ly9vY3NwLnNhdC5nb2IubXgvMB8GA1UdIwQYMBaAFOtZfQQimlONnnEaoFiW" "KfU54KDFMBAGA1UdIAQJMAcwBQYDKgMEMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0G" "CSqGSIb3DQEBBQUAA4IBAQArHQEorApwqumSn5EqDOAjbezi8fLco1cYES/PD+LQ" "RM1Vb1g7VLE3hR4S5NNBv0bMwwWAr0WfL9lRRj0PMKLorO8y4TJjRU8MiYXfzSuK" "YL5Z16kW8zlVHw7CtmjhfjoIMwjQo3prifWxFv7VpfIBstKKShU0qB6KzUUNwg2O" "la4t4gg2JJcBmyIAIInHSGoeinR2V1tQ10aRqJdXkGin4WZ75yMbQH4L0NfotqY6" "bpF2CqIY3aogQyJGhUJji4gYnS2DvHcyoICwgawshjSaX8Y0Xlwnuh6EusqhqlhT" "gwPNAPrKIXCmOWtqjlDhho/lhkHJMzuTn8AoVapbBUnj" "-----END CERTIFICATE-----"; keyfile = "-----BEGIN ENCRYPTED PRIVATE KEY-----" "MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQInuASOYqnkMoCAggA" "MBQGCCqGSIb3DQMHBAhXp9z9DSW2PgSCAoAQVlA5ii7OMeprchNs4wwgE2ReNZrw" "yVvFISJpnCN4Y906w/MYvpoc5J8q5eIZi9R5Y+FPBaCkprN0w54ypMYQX9oPuSlk" "KW5C7LCq5d1mx4ZeGDmqCNXesehi/kY/0Mt/m8CB90x8dwKVE3bLJVwi+IgbgLf5" "zStnIXs/LTiA3a9B0Yo8Oe6J4q+Kt0Dlg0+JfSekP76BmImpScc6lUClOX54pCCr" "gOOZpdJK7G9u/UpxfVdAQeL2GaLE3tfxlEHuFtHmkXMy51OuSv7er+9FuNMxCYGa" "rLiUybDuFlvcV7++9aVql/Qao5gGgKZ1oeCJNb1DZ4xdKJedtx0Kzrp3JmTeSNmG" "yzkbczFEM1m2GhPQGD6uadqMCguIwlHHm46s/jWBdEjhuQaedbwcQUiOn20dsfh5" "F1Ld3aMDqAXaJdqhqsXrehMXDdHoTV8c6x66cDXAqiJGng6jySDe/sNMtlX1fHiw" "6mjq12Wu5E8bmlzHXy8BO4zJS9qgYec34UK30sFk3ZhBXM8ALq2cn1JkGxDDkqjv" "dOOocARME+dxNHxw6rw0UESi0i5GtwYRL8eLHuPPJN7zcQG8FytGI8CsTMYSe72L" "v0EFacZv7UOQde0vLww8A4EieDLxMu25mZAZ9DebFQwSHtiS4NK5PHFTk4Tm2vEr" "X/HZfMQmDQbqG8v/cNNKGX/OGcIVu9eLY7T55OG1n1O2bofVkjZ0gzgAo7ZCWMqX" "f/17dljEIQ/b9iHESwri/Lw5g9cQBBAx23pNPP2SteGhvQg50ZyrxGA5/an1ti2Z" "u5nQ+7YpPyrKxjERRjk8B8i2qLxDrJuaDHfAOWTvdVoGX9/s7M2p68B6" "-----END ENCRYPTED PRIVATE KEY-----"; password = "a0123456789"; ret = SAT_CheckKeyAndCert(keyfile, password, certfile, 0); printf("SAT_CheckKeyAndCert(STRINGS) returns %ld\n", ret); if (ret != 0) disp_error(ret); assert(ret == 0); printf("\nGET RECEIPT (COMPROBANTE) VERSION NUMBER FROM XML FILE: \n"); fname = "Muestra_v2_base2011.xml"; ret = SAT_XmlReceiptVersion(fname, 0); printf("SAT_XmlReceiptVersion(%s)=%ld\n", fname, ret); if (ret <= 0) disp_error(ret); assert (2 == ret); fname = "ejemplo_v3_base2011.xml"; ret = SAT_XmlReceiptVersion(fname, 0); printf("SAT_XmlReceiptVersion(%s)=%ld\n", fname, ret); if (ret <= 0) disp_error(ret); assert (3 == ret); // New in [v5.0]... fname = "Muestra_v22-base.xml"; ret = SAT_XmlReceiptVersion(fname, 0); printf("SAT_XmlReceiptVersion(%s)=%ld\n", fname, ret); if (ret <= 0) disp_error(ret); assert (22 == ret); fname = "ejemplo_v32-base.xml"; ret = SAT_XmlReceiptVersion(fname, 0); printf("SAT_XmlReceiptVersion(%s)=%ld\n", fname, ret); if (ret <= 0) disp_error(ret); assert (32 == ret); // NEW IN [v4.0] ... // Show we can now cope with CFDi XML with no prefixes fname = "ejemplo_v3_noprefix.xml"; ret = SAT_XmlReceiptVersion(fname, 0); printf("SAT_XmlReceiptVersion(%s)=%ld\n", fname, ret); if (ret <= 0) disp_error(ret); assert (3 == ret); printf("\nCREATE CADENA ORIGINAL DEL TIMBRE FISCAL DIGITAL (PIPESTRING FOR TFD): \n"); fname = "ejemplo_v3_tfd.xml"; nchars = SAT_MakePipeStringFromXml(NULL, 0, fname, SAT_TFD); printf("SAT_MakePipeStringFromXml(%s, SAT_TFD) returns %ld\n", fname, nchars); if (nchars >= 0) { buf = malloc(nchars+1); nchars = SAT_MakePipeStringFromXml(buf, nchars, fname, SAT_TFD); printf("%s\n", buf); free(buf); } else disp_error(nchars); assert(nchars > 0); printf("\nFORM DIGEST OF PIPESTRING FOR TFD: \n"); fname = "ejemplo_v3_tfd.xml"; ret = SAT_MakeDigestFromXml(digest, sizeof(digest)-1, fname, SAT_TFD); printf("SAT_MakeDigestFromXml returns %ld\n", ret); if (ret < 0) disp_error(ret); printf("SAT_MakeDigestFromXml(%s, SAT_TFD)=\n%s\n", fname, digest); assert (ret > 0); printf("\nEXTRACT DIGEST FROM TFD SELLOSAT: \n"); fname = "ejemplo_v3_tfd.xml"; certfile = "aaa010101aaa_CSD_02.cer"; // NB certificate is required for TFD option ret = SAT_ExtractDigestFromSignature(digest1, sizeof(digest1)-1, fname, certfile, SAT_TFD); printf("SAT_ExtractDigestFromSignature returns %ld\n", ret); if (ret < 0) disp_error(ret); printf("SAT_ExtractDigestFromSignature(%s, SAT_TFD)=\n%s\n", fname, digest1); assert (ret > 0); /* check that the two digests match (CAUTION: upper- vs lower-case) */ assert (_stricmp(digest, digest1) == 0); printf("\nPRETEND WE ARE A PAC WITH A KEY ALLOWED TO SIGN THE TFD: \n"); fname = "ejemplo_v3_tfd.xml"; keyfile = "aaa010101aaa_CSD_02.key"; password = "a0123456789"; /* CAUTION: DO NOT HARD-CODE REAL PASSWORDS! */ nchars = SAT_MakeSignatureFromXmlEx(NULL, 0, fname, keyfile, password, SAT_TFD); if (nchars >= 0) { buf = malloc(nchars+1); nchars = SAT_MakeSignatureFromXmlEx(buf, nchars, fname, keyfile, password, SAT_TFD); printf("SAT_MakeSignatureFromXmlEx(%s,%s,SAT_TFD)=\n%s\n", fname, keyfile, buf); // free(buf); // Save for later... } else disp_error(nchars); assert(nchars > 0); // Extract the correct signature field from the XML... fname = "ejemplo_v3_tfd.xml"; elementName = "tfd:TimbreFiscalDigital"; attributeName = "selloSAT"; nchars = SAT_GetXmlAttribute(NULL, 0, fname, attributeName, elementName); if (nchars >= 0) { buf1 = malloc(nchars+1); nchars = SAT_GetXmlAttribute(buf1, nchars, fname, attributeName, elementName); printf("SAT_GetXmlAttribute(%s,%s,%s)=\n%s\n", fname, attributeName, elementName, buf1); // free(buf); // Save for later... } else disp_error(nchars); assert(nchars > 0); // Check against the correct answer assert(strcmp(buf, buf1) == 0); free(buf); free(buf1); printf("\nVERIFY SIGNATURE IN TFD SELLOSAT: \n"); fname = "ejemplo_v3_tfd.xml"; certfile = "aaa010101aaa_CSD_02.cer"; ret = SAT_VerifySignature(fname, certfile, SAT_TFD); printf("SAT_VerifySignature(%s,%s,SAT_TFD')=%ld \n(expected 0)\n", fname, certfile, ret); assert (ret == 0); // New in [v4.1] printf("\nADD UTF-8 BOM TO EXISTING FILE:\n"); fname = "Muestra_v2_signed2011.xml"; newname = "Muestra_v2_with_BOM.xml"; n = SAT_FixBOM(newname, fname, 0); printf("SAT_FixBOM(%s->%s})=%ld (expected 0)\n", fname, newname, n); assert(n == 0); // NEW IN [v5.0]... printf("\nEXTRACT ATTRIBUTES FROM CONSECUTIVE ELEMENTS:\n"); fname = "ejemplo_v3_base2011.xml"; attributeName = "descripcion"; elementName = "cfdi:Concepto"; printf("For file '%s'\n", fname); for (i = 1; i <= 100; i++) { char s[64]; sprintf(eName, "%s[%d]", elementName, i); SAT_GetXmlAttribute(s, sizeof(s)-1, fname, attributeName, eName); printf("SAT_GetXmlAttribute(%s,%s)=%s\n", attributeName, eName, s); if (strlen(s) == 0) { break; } } printf("\nDETECT VERSION 2.2 OR 3.2 AUTOMATICALLY AND SIGN:\n"); certfile = "aaa010101aaa_CSD_01.cer"; keyfile = "aaa010101aaa_CSD_01.key"; password = "a0123456789"; fname = "Muestra_v22-base.xml"; newname = "Muestra_v22-new_signed.xml"; n = SAT_SignXml(newname, fname, keyfile, password, certfile, 0); printf("SAT_SignXml('%s'-->'%s') returns %ld\n", fname, newname, n); assert(n == 0); // Did we make a valid XML file? n = SAT_ValidateXml(newname, 0); printf("Sat.SAT_ValidateXml('%s') returns %ld\n", newname, n); assert(n == 0); fname = "V2_2-base.xml"; newname = "V2_2-new_signed.xml"; n = SAT_SignXml(newname, fname, keyfile, password, certfile, 0); printf("SAT_SignXml('%s'-->'%s') returns %ld\n", fname, newname, n); assert(n == 0); // Did we make a valid XML file? n = SAT_ValidateXml(newname, 0); printf("Sat.SAT_ValidateXml('%s') returns %ld\n", newname, n); assert(n == 0); fname = "ejemplo_v32-base.xml"; newname = "ejemplo_v32-new_signed.xml"; n = SAT_SignXml(newname, fname, keyfile, password, certfile, 0); printf("SAT_SignXml('%s'-->'%s') returns %ld\n", fname, newname, n); assert(n == 0); // Did we make a valid XML file? n = SAT_ValidateXml(newname, 0); printf("Sat.SAT_ValidateXml('%s') returns %ld\n", newname, n); assert(n == 0); fname = "V3_2-base.xml"; newname = "V3_2-new_signed.xml"; n = SAT_SignXml(newname, fname, keyfile, password, certfile, 0); printf("SAT_SignXml('%s'-->'%s') returns %ld\n", fname, newname, n); assert(n == 0); // Did we make a valid XML file? n = SAT_ValidateXml(newname, 0); printf("Sat.SAT_ValidateXml('%s') returns %ld\n", newname, n); assert(n == 0); printf("\nVALIDATE XML WITH STRICT AND LOOSE OPTIONS:\n"); printf("Default strict behaviour (badly formed CURP attribute):\n"); fname = "V3_2_BadCurp.xml"; n = SAT_ValidateXml(fname, 0); printf("SAT_ValidateXml('%s') returns %ld\n", fname, n); disp_error(n); assert(n != 0); printf("\nUsing XmlOption.Loose:\n"); n = SAT_ValidateXml(fname, SAT_XML_LOOSE); printf("Sat.SAT_ValidateXml('%s', LOOSE) returns %ld\n", fname, n); assert(n == 0); printf("\nGET PRIVATE KEY AS BASE64:\n"); fname = "aaa010101aaa_CSD_01.key"; password = "a0123456789"; nchars = SAT_GetKeyAsString(NULL, 0, fname, password, 0); assert(nchars > 0); buf = malloc(nchars+1); nchars = SAT_GetKeyAsString(buf, nchars, fname, password, 0); printf("SAT_GetKeyAsString(%s)=\n%s\n", fname, buf); printf("SAT_GetKeyAsString(%s) length=%d\n", fname, nchars); // Finally, display current DLL version SAT_CompileTime(cdate, sizeof(cdate)-1); printf("\nFirmaSAT version=%ld [%s]\n", SAT_Version(), cdate); // Change "#if 0" to "#if 1" to activate this #if 0 printf("\nDISPLAY ALL POSSIBLE ERROR MESSAGES:\n"); display_all_errors(); #endif printf("\nALL DONE.\n"); return 0; } void display_all_errors(void) { long i, nchars; char errbuf[256]; for (i = 0; i < 10000; i++) { nchars = SAT_ErrorLookup(errbuf, sizeof(errbuf)-1, i); if (nchars > 0) printf("%ld=>%s\n", i, errbuf); } }