CryptoSys Home > FirmaSAT > The logic behind the FirmaSAT On-line Validator

The logic behind the FirmaSAT On-line Validator


This page explains the logic behind the FirmaSAT On-line Validator and shows the function calls from the FirmaSAT library.

Example output

Validator results

Example input files

Input XML file (Combrobante archivo XML): fname = "Prueba2Notario_iedu-tfd.xml"
PAC X.509 Certificate (Certificado del SAT): certname = "pac.cer"

Procedure

Each step of the procedure is described below. A simplified copy of the original C/C++ code is given together with the relevant C# code statements and the closest command-line instruction.

  1. Checking the version
  2. Checking the XML structure
  3. Getting the original string ("piped string"/cadena orginal)
  4. Getting the digest of the original string in hexadecimal
  5. Getting the certificate serial numbers
  6. Is the signature valid?
  7. Do we have a TimbreFiscalDigital (TFD) element?
  8. Getting the TFD original string of certification
  9. Getting the digest of the original certification string in hexadecimal
  10. Getting the certificate serial numbers used for the TimbreFiscalDigital
  11. Is the TFD signature valid?
  12. Display the version of FirmaSAT used
Code in C/C++ is shown in the form
long receiptver = SAT_XmlReceiptVersion(fname, 0);
Code in C# is shown in the form
int receiptver = Sat.XmlReceiptVersion(fname);
The closest command-line instruction is shown in the form
FirmaSAT RECEIPTVERSION fname.xml

VB6/VBA programmers should be able to figure out their equivalent code from the C code. Similarly, VB.NET and Java programmers should be able to derive their code from the C# code. The command-line instructions should at least give an idea as to how to derive the required information.

1. Checking the version

Version

Reference: Get XML Receipt Version Number

long receiptver = SAT_XmlReceiptVersion(fname, 0);
switch (receiptver) {
case 2:
    recverstr = "2.0";
    doctype = "CFD";
    is_cfdi = 0;
    break;
case 3:
    recverstr = "3.0";
    doctype = "CFDI";
    is_cfdi = 1;
    break;
case 22:
    recverstr = "2.2";
    doctype = "CFD";
    is_cfdi = 0;
    break;
case 32:
    recverstr = "3.2";
    doctype = "CFDI";
    is_cfdi = 1;
    break;
default:
    ERROR();
    break;
}
printf("%s standard version: %s\n", doctype, recverstr);
int receiptver = Sat.XmlReceiptVersion(fname);
FirmaSAT RECEIPTVERSION fname.xml
2. Checking the XML structure

XML Structure

References: Validate XML Document, Error-related procedures

r = SAT_ValidateXml(fname, 0);
if (0 == r) {
    printf("XML structure is valid\n");
} else {
    printf("XML structure is NOT valid\n");
    SAT_LastError(errbuf, SAT_MAX_ERROR_CHARS);
    printf("%s\n", errbuf);
    // But only quit if it does not pass the "loose" test
    r = SAT_ValidateXml(fname, SAT_XML_LOOSE);
    if (r != 0) ERROR();
}
r = Sat.ValidateXml(fname);
errbuf = General.LastError();  
r = Sat.ValidateXml(fname, XmlOption.Loose);
FirmaSAT XMLOK fname.xml
FirmaSAT XMLOK -l fname.xml
3. Getting the original string ("pipe string"/cadena orginal)

Original string

Reference: Make Pipe String

nchars = SAT_MakePipeStringFromXml(NULL, 0, fname, 0);
if (nchars < 0) ERROR(); 
pipebuf = MALLOC(nchars+1);
nchars = SAT_MakePipeStringFromXml(pipebuf, nchars, fname, 0);
string pipebuf = Sat.MakePipeStringFromXml(fname);
if (pipebuf.Length == 0) ERROR();
FirmaSAT PIPESTRING fname.xml
4. Getting the digest of the original string in hexadecimal

Digest in hex

Reference: Make Digest

char digest[SAT_MAX_HASH_CHARS+1] = { 0 };
r = SAT_MakeDigestFromXml(digest, sizeof(digest)-1, fname, 0);
printf("%s\n", digest);
string digest = Sat.MakeDigestFromXml(fname);
Console.WriteLine("{0}", digest);
FirmaSAT FORMDIGEST fname.xml
5. Getting the certificate serial numbers

Certificate serial numbers

References: Query a Certificate, Get XML Attribute

char certused[32] = { 0 };
char certrept[32] = { 0 };
r = SAT_QueryCert(certused, sizeof(certused)-1, fname, "serialNumber", 0);
printf("Certificate used:     %s\n, certused);
r = SAT_GetXmlAttribute(certrept, sizeof(certrept)-1, fname, "noCertificado", "Comprobante");
printf("Certificate reported: %s\n, certrept);
string certused = Sat.QueryCert(fname, Query.serialNumber);
Console.WriteLine("Certificate used:     {0}", certused);
string certrept = Sat.GetXmlAttribute(fname, "noCertificado", "Comprobante");
Console.WriteLine("Certificate reported: {0}", certrept);
FirmaSAT QUERYCERT -q serialNumber fname.xml
FirmaSAT ATTRIBUTE -a noCertificado -e Comprobante fname.xml
6. Is the signature valid?

Is signature valid

Reference: Verify XML Signature

r = SAT_VerifySignature(fname, NULL, 0);
if (0 == r) {
    printf("The %s signature is valid\n", doctype);
} else {
    printf("The %s signature is NOT valid\n", doctype);
    ERROR();
}
r = Sat.VerifySignature(fname);
FirmaSAT VERIFYSIG fname.xml
7. Do we have a TimbreFiscalDigital (TFD) element?
if (is_cfdi) {  // See step 1
    long r = SAT_GetXmlAttribute(NULL, 0, fname, "selloCFD", "tfd:TimbreFiscalDigital");
    if (r < 0) ERROR("the TFD signature is missing");
}
string s = Sat.GetXmlAttribute(fname, "selloCFD", "tfd:TimbreFiscalDigital");
if (s.Length == 0) ERROR("the TFD signature is missing");
FirmaSAT ATTRIBUTE -a selloCFD -e tfd:TimbreFiscalDigital fname.xml
8. Getting the TFD original string of certification

TFD original string of certification

Reference: Timbre Fiscal Digital (TFD) element

nchars = SAT_MakePipeStringFromXml(NULL, 0, fname, SAT_TFD);
if (nchars < 0) ERROR(); 
pipebuf = MALLOC(nchars+1);
nchars = SAT_MakePipeStringFromXml(pipebuf, nchars, fname, SAT_TFD);
string pipebuf = Tfd.MakePipeStringFromXml(fname);
if (pipebuf.Length == 0) ERROR();
FirmaSAT PIPESTRING -f fname.xml
9. Getting the digest of the original certification string in hexadecimal

Digest of string of certification

char digest[SAT_MAX_HASH_CHARS+1] = { 0 };
r = SAT_MakeDigestFromXml(digest, sizeof(digest)-1, fname, SAT_TFD);
printf("%s\n", digest);
string digest = Tfd.MakeDigestFromXml(fname);
Console.WriteLine("{0}", digest);
FirmaSAT FORMDIGEST -f fname.xml
10. Getting the certificate serial numbers used for the TimbreFiscalDigital

TFD certificate serial numbers

char certused[32] = { 0 };
char certrept[32] = { 0 };
r = SAT_QueryCert(certused, sizeof(certused)-1, certname, "serialNumber", 0);
printf("Certificate used:     %s\n, certused);
r = SAT_GetXmlAttribute(certrept, sizeof(certrept)-1, fname, "noCertificadoSAT", "tfd:TimbreFiscalDigital");
printf("Certificate reported: %s\n, certrept);
string certused = Sat.QueryCert(certname, Query.serialNumber);
Console.WriteLine("Certificate used:     {0}", certused);
string certrept = Sat.GetXmlAttribute(fname, "noCertificadoSAT", "tfd:TimbreFiscalDigital");
Console.WriteLine("Certificate reported: {0}", certrept);
FirmaSAT QUERYCERT -q serialNumber certname.cer
FirmaSAT ATTRIBUTE -a noCertificadoSAT -e tfd:TimbreFiscalDigital fname.xml
11. Is the TFD signature valid?

Is TFD signature valid

r = SAT_VerifySignature(fname, certname, SAT_TFD);
if (0 == r) {
    printf("The TFD signature is valid\n");
} else {
    printf("The TFD signature is NOT valid\n");
    ERROR();
}
r = Tfd.VerifySignature(fname, certname);
FirmaSAT VERIFYSIG -f -c certname.cer fname.xml
12. Display the version of FirmaSAT used

Display FirmaSAT version

printf("Produced using FirmaSAT v.%ld.", SAT_Version());
Console.WriteLine("Produced using FirmaSAT v.{0}", General.Version());
FirmaSAT LIBINFO

Getting FirmaSAT

You can download a fully-functional trial version of FirmaSAT from here.

Contact

To comment on this page, make a suggestion for improvement, or for further information, please send us a message.

This page last updated 15 August 2025.