Attribute VB_Name = "TestFirmaSAT"

' **************************** COPYRIGHT NOTICE ****************************
' * Copyright (C) 2010-12 DI Management Services Pty Limited.
' * All rights reserved. <www.di-mgt.com.au> <www.cryptosys.net>
' *   $Id: TestFirmaSAT.bas $
' *   Last updated:
'   $Date: 2012-03-23 15:44 $
'   $Revision: 5.1.0 $
' ************************* END OF COPYRIGHT NOTICE ************************

' Some tests using the FirmaSAT VB6/VBA interface.
' Requires certain files to exist in the current working directory.
' Direct calls to the DLL begin with "SAT_", wrapper functions begin with "sat" or "tfd"

' [v2.1] Added options for SHA-1 message digest algorithm
' [v3.0] Added new functions and support for CFDI version 3.0 XML documents
' [v4.0] Added support for selloSAT signatures in the TFD node. Removed dependency on CryptoSys PKI.
' [v4.1] Added SAT_FixBOM function.
' [v5.0] Added support for version 2.2 and 3.2. Added GetKeyAsString function.
' [v5.1] Added WritePfx and QueryCert functions.

Option Explicit
Option Base 0

Public Sub General_Tests()
    Dim n As Long
    Dim i As Long
    Dim s As String
    Dim s1 As String
    Dim ch As String
    Dim fname As String
    Dim newname As String
    Dim keyfile As String
    Dim certfile As String
    Dim password As String
    Dim newpassword As String
    Dim attributeName As String
    Dim elementName As String
    Dim eName As String
    
    ' Check if all required test files exist in the CWD
    If Not RequiredFilesExist() Then
        MsgBox "Required test file cannot be found in current working directory: " & CurDir, vbCritical
        Exit Sub
    End If
    
    Debug.Print ("INTERROGATE THE CORE DIFIRMASAT DLL:")
    n = SAT_Version()
    Debug.Print "Version=" & n
    If n < 400 Then
        MsgBox "Require FirmaSAT v4.0 or higher", vbCritical
        Exit Sub
    End If
    ch = Chr(SAT_LicenceType())
    Debug.Print "LicenceType=" & ch
    Debug.Print "ModuleName=" & satModuleName()
    Debug.Print "CompileTime=" & satCompileTime()

    ' NOTE: as of [v4.0] these functions are redundant.
    ''Debug.Print (vbLf & "Interrogate the underlying CryptoSys PKI DLL:")
    ''n = SAT_PKIVersion()
    ''Debug.Print "SAT_PKIVersion returns " & n
    ''Debug.Print "PKIModuleName=" & satPKIModuleName()
    ''Debug.Print "PKICompileTime=" & satPKICompileTime()
    
    Debug.Print (vbLf & "FORM THE PIPESTRING FROM AN XML FILE:")
    fname = "Muestra_v2_signed2011.xml"
    s = satMakePipeStringFromXml(fname)
    Debug.Print "MakePipeStringFromXml(" & fname & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "SAT_MakePipeStringFromXml failed")
    
    Debug.Print (vbLf & "SIGN AN XML FILE:")
    fname = "Muestra_v2_base2011.xml"
    newname = "Muestra_v2_signed_new.xml"
    keyfile = "aaa010101aaa_CSD_01.key"
    password = "a0123456789"    ' CAUTION: DO NOT HARD-CODE REAL PASSWORDS!
    certfile = "aaa010101aaa_CSD_01.cer"
    n = SAT_SignXml(newname, fname, keyfile, password, certfile, 0)
    Debug.Print "SAT_SignXml('" & fname & "'-->'" & newname & "') returns " & n
    Call Our_Assert(n = 0, "SAT_SignXml failed")
    ' Did we make a valid XML file?
    n = SAT_ValidateXml(newname, 0)
    Debug.Print "SAT_ValidateXml(" & newname & ") returns " & n
    Call Our_Assert(n = 0, "SAT_ValidateXml failed")

    Debug.Print (vbLf & "VERIFY A SIGNATURE IN AN XML FILE:")
    Debug.Print ("1. One we know is good:")
    fname = "Muestra_v2_signed2011.xml"
    n = satVerifySignature(fname)
    Debug.Print "SAT_VerifySignature(" & fname & ") returns " & n
    Call Our_Assert(n = 0, "SAT_VerifySignature failed")

    Debug.Print ("2. One we just made, so it should be good:")
    fname = newname
    n = satVerifySignature(fname)
    Debug.Print "SAT_VerifySignature(" & fname & ") returns " & n
    Call Our_Assert(n = 0, "SAT_VerifySignature failed")
    
    Debug.Print (vbLf & "FORM THE DIGEST OF THE PIPESTRING IN AN XML FILE:")
    fname = "Muestra_v2_signed2011.xml"
    s = satMakeDigestFromXml(fname)
    Debug.Print "MakeDigestFromXml(" & fname & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "SAT_MakeDigestFromXml failed")

    Debug.Print (vbLf & "EXTRACT THE DIGEST FROM THE SIGNATURE IN AN XML FILE:")
    fname = "Muestra_v2_signed2011.xml"
    s1 = satExtractDigestFromSignature(fname)
    Debug.Print "ExtractDigestFromSignature(" & fname & ")=" & vbLf & s1
    Call Our_Assert(Len(s1) > 0, "SAT_ExtractDigestFromSignature failed")

    Call Our_Assert(StrComp(s1, s, vbTextCompare) = 0, "CFD Digests do not match")
    
    Debug.Print (vbLf & "TRY VALIDATING XML FILES:")
    Debug.Print ("1. A valid one:")
    fname = "Muestra_v2_signed2011.xml"
    n = SAT_ValidateXml(fname, 0)
    Debug.Print "SAT_ValidateXml(" & fname & ") returns " & n
    Call Our_Assert(n = 0, "SAT_ValidateXml failed")
    
    Debug.Print ("2. An invalid one:")
    fname = "Muestra_v2_bad.xml"
    n = SAT_ValidateXml(fname, 0)
    Debug.Print "SAT_ValidateXml(" & fname & ") returns " & n
    s = satLastError()
    Debug.Print "ErrorLookup(" & n & ")=" & satErrorLookup(n)
    Debug.Print "LastError=" & s

    Debug.Print (vbLf & "EXTRACT AN ATTRIBUTE FROM AN XML FILE:")
    fname = "Muestra_v2_signed2011.xml"
    elementName = "Comprobante"
    attributeName = "sello"
    s = satGetXmlAttribute(fname, attributeName, elementName)
    Debug.Print "SAT_GetXmlAttribute('" & fname & "'," & attributeName & "," & elementName & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "SAT_GetXmlAttribute failed")
    
    Debug.Print (vbLf & "GET DETAILS OF X.509 CERTIFICATE:")
    Debug.Print ("1. From embedded `certificado` in XML")
    fname = "Muestra_v2_signed2011.xml"
    s = satGetCertNumber(fname)
    Debug.Print "GetCertNumber(" & fname & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "SAT_GetCertNumber failed")
    s = satGetCertExpiry(fname)
    Debug.Print "GetCertExpiry(" & fname & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "SAT_GetCertExpiry failed")
    ' [v3.0] added this...
    s = satGetCertStart(fname)
    Debug.Print "satGetCertStart(" & fname & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "satGetCertStart failed")

    Debug.Print ("2. From X.509 file")
    fname = "aaa010101aaa_CSD_01.cer"
    s = satGetCertNumber(fname)
    Debug.Print "GetCertNumber(" & fname & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "SAT_GetCertNumber failed")
    s = satGetCertExpiry(fname)
    Debug.Print "GetCertExpiry(" & fname & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "SAT_GetCertExpiry failed")
    ' [v3.0] added this...
    s = satGetCertStart(fname)
    Debug.Print "satGetCertStart(" & fname & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "satGetCertStart failed")
    
    Debug.Print (vbLf & "GET CERTIFICATE AS A BASE64 STRING:")
    fname = "aaa010101aaa_CSD_01.cer"
    s = satGetCertAsString(fname)
    Debug.Print "GetCertAsString(" & fname & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "SAT_GetCertAsString failed")
    Debug.Print "Len(GetCertAsString(" & fname & "))=" & Len(s)
    ' Compare against string from XML file
    fname = "Muestra_v2_signed2011.xml"
    s1 = satGetCertAsString(fname)
    Debug.Print "Len(GetCertAsString(" & fname & "))=" & Len(s1)
    Call Our_Assert(Len(s1) > 0, "SAT_GetCertAsString failed")
    Call Our_Assert(StrComp(s, s1, vbTextCompare) = 0, "SAT_GetCertAsString failed")

    Debug.Print (vbLf & "MAKE A SIGNATURE FROM A BASE XML FILE:")
    fname = "Muestra_v2_base2011.xml"
    keyfile = "aaa010101aaa_CSD_01.key"
    password = "a0123456789"    ' CAUTION: DO NOT HARD-CODE REAL PASSWORDS!
    s = satMakeSignatureFromXml(fname, keyfile, password)
    Debug.Print "MakeSignatureFromXml(" & fname & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "SAT_MakeSignatureFromXml failed")

    Debug.Print (vbLf & "SIGN A DETALLISTA XML FILE:")
    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"
    n = SAT_SignXml(newname, fname, keyfile, password, certfile, 0)
    Debug.Print "SAT_SignXml('" & fname & "'-->'" & newname & "') returns " & n
    Call Our_Assert(n = 0, "SAT_SignXml failed")
    ' Did we make a valid XML file?
    n = SAT_ValidateXml(newname, 0)
    Debug.Print "SAT_ValidateXml(" & newname & ") returns " & n
    Call Our_Assert(n = 0, "SAT_ValidateXml failed")
    n = satVerifySignature(newname)
    Debug.Print "SAT_VerifySignature(" & newname & ") returns " & n
    Call Our_Assert(n = 0, "SAT_VerifySignature failed")
    
    Debug.Print (vbLf & "EXTRACT AN ATTRIBUTE FROM A DETALLISTA XML FILE:")
    fname = "detallista-new-signed.xml"
    elementName = "detallista:detallista"
    attributeName = "documentStructureVersion"
    s = satGetXmlAttribute(fname, attributeName, elementName)
    Debug.Print "SAT_GetXmlAttribute('" & fname & "'," & attributeName & "," & elementName & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "SAT_GetXmlAttribute failed")
    Call Our_Assert(StrComp(s, "AMC8.1") = 0, "Invalid detallista.documentStructureVersion")
    
    ' [NEW IN VERSION 3.0] WILL NOW SIGN CFDI Version="3.0" XML
    ' [v3.0] Default digest algorithm is now SHA-1
    
    Debug.Print (vbLf & "SIGN CFDI VERSION 3.0 XML FILE:")
    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"
    n = SAT_SignXml(newname, fname, keyfile, password, certfile, 0)
    Debug.Print "SAT_SignXml('" & fname & "'-->'" & newname & "') returns " & n
    Call Our_Assert(n = 0, "SAT_SignXml failed")
    ' Did we make a valid XML file?
    n = SAT_ValidateXml(newname, 0)
    Debug.Print "SAT_ValidateXml(" & newname & ") returns " & n
    Call Our_Assert(n = 0, "SAT_ValidateXml failed")
    
    Debug.Print (vbLf & "VERIFY A SHA-1 SIGNATURE IN AN XML FILE:")
    fname = newname
    n = satVerifySignature(fname)
    Debug.Print "SAT_VerifySignature(" & fname & ") returns " & n
    Call Our_Assert(n = 0, "SAT_VerifySignature failed")
    
    Debug.Print (vbLf & "EXTRACT THE DIGEST FROM THE SIGNATURE IN AN XML FILE:")
    fname = "ejemplo_v3_signed-new.xml"
    s = satExtractDigestFromSignature(fname)
    Debug.Print "ExtractDigestFromSignature(" & fname & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "SAT_ExtractDigestFromSignature failed")
    
    Debug.Print (vbLf & "FORM THE DIGEST OF THE PIPESTRING IN AN XML FILE:")
    fname = "ejemplo_v3_signed-new.xml"
    s1 = satMakeDigestFromXml(fname, SAT_HASH_SHA1)
    Debug.Print "MakeDigestFromXml(" & fname & ")=" & vbLf & s1
    Call Our_Assert(Len(s1) > 0, "SAT_MakeDigestFromXml failed")
    
    Call Our_Assert(StrComp(s1, s, vbTextCompare) = 0, "CFDi Digests do not match")
    
    Debug.Print (vbLf & "EXTRACT AN ATTRIBUTE FROM A v3.0 XML FILE:")
    fname = "ejemplo_v3_signed-new.xml"
    elementName = "cfdi:Comprobante"
    attributeName = "sello"
    s = satGetXmlAttribute(fname, attributeName, elementName)
    Debug.Print "SAT_GetXmlAttribute('" & fname & "'," & attributeName & "," & elementName & ")=" & vbLf & s
    Call Our_Assert(Len(s) > 0, "SAT_GetXmlAttribute failed")
    
    ' [v3.0] NEW FUNCTIONS ADDED...
    
    Debug.Print (vbLf & "CHECK PRIVATE KEY MATCHES PUBLIC KEY IN CERTIFICATE:")
    certfile = "aaa010101aaa_CSD_01.cer"
    keyfile = "aaa010101aaa_CSD_01.key"
    password = "a0123456789"   ' CAUTION: DO NOT HARD-CODE REAL PASSWORDS!
    n = SAT_CheckKeyAndCert(keyfile, password, certfile, 0)
    Debug.Print "SAT_CheckKeyAndCert(" & keyfile & "," & certfile & ")=" & n
    Call Our_Assert(n = 0, "SAT_CheckKeyAndCert failed")
    
    certfile = "aaa010101aaa_CSD_02.cer"
    keyfile = "aaa010101aaa_CSD_02.key"
    password = "a0123456789"
    n = SAT_CheckKeyAndCert(keyfile, password, certfile, 0)
    Debug.Print "SAT_CheckKeyAndCert(" & keyfile & "," & certfile & ")=" & n
    Call Our_Assert(n = 0, "SAT_CheckKeyAndCert failed")

    ' Get embedded certificate from XML doc
    certfile = "Muestra_v2_signed2011.xml"
    keyfile = "aaa010101aaa_CSD_01.key"
    password = "a0123456789"
    n = SAT_CheckKeyAndCert(keyfile, password, certfile, 0)
    Debug.Print "SAT_CheckKeyAndCert(" & keyfile & "," & certfile & ")=" & n
    Call Our_Assert(n = 0, "SAT_CheckKeyAndCert failed")
    
    ' 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+WgAwIBAgIUMzAwMDEwMDAwMDAxMDAwMDA4MDAwDQYJKoZIhvcNAQEFBQAwggFvMRgwFgYDVQQDDA9BLkMuIGRlIHBydWViYXMxLzAtBgNVBAoMJlNlcnZpY2lvIGRlIEFkbWluaXN0cmFjacOzbiBUcmlidXRhcmlhMTgwNgYDVQQLDC9BZG1pbmlzdHJhY2nDs24gZGUgU2VndXJpZGFkIGRlIGxhIEluZm9ybWFjacOzbjEpMCcG" & _
        "CSqGSIb3DQEJARYaYXNpc25ldEBwcnVlYmFzLnNhdC5nb2IubXgxJjAkBgNVBAkMHUF2LiBIaWRhbGdvIDc3LCBDb2wuIEd1ZXJyZXJvMQ4wDAYDVQQRDAUwNjMwMDELMAkGA1UEBhMCTVgxGTAXBgNVBAgMEERpc3RyaXRvIEZlZGVyYWwxEjAQBgNVBAcMCUNveW9hY8OhbjEVMBMGA1UELRMMU0FUOTcwNzAxTk4zMTIwMAYJKoZIhvcNAQkC" & _
        "DCNSZXNwb25zYWJsZTogSMOpY3RvciBPcm5lbGFzIEFyY2lnYTAeFw0xMDA3MzAxNjU4NDBaFw0xMjA3MjkxNjU4NDBaMIGWMRIwEAYDVQQDDAlNYXRyaXogU0ExEjAQBgNVBCkMCU1hdHJpeiBTQTESMBAGA1UECgwJTWF0cml6IFNBMSUwIwYDVQQtExxBQUEwMTAxMDFBQUEgLyBBQUFBMDEwMTAxQUFBMR4wHAYDVQQFExUgLyBBQUFBMDEw" & _
        "MTAxSERGUlhYMDExETAPBgNVBAsMCFVuaWRhZCAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDD0ltQNthUNUfzq0t1GpIyapjzOn1W5fGM5G/pQyMluCzP9YlVAgBjGgzwYp9Z0J9gadg3y2ZrYDwvv8b72goyRnhnv3bkjVRKlus6LDc00K7Jl23UYzNGlXn5+i0HxxuWonc2GYKFGsN4rFWKVy3Fnpv8Z2D7dNqsVyT5HapEqwIDAQAB" & _
        "o4HqMIHnMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgbAMB0GA1UdDgQWBBSYodSwRczzj5H7mcO3+mAyXz+y0DAuBgNVHR8EJzAlMCOgIaAfhh1odHRwOi8vcGtpLnNhdC5nb2IubXgvc2F0LmNybDAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNhdC5nb2IubXgvMB8GA1UdIwQYMBaAFOtZfQQimlONnnEaoFiW" & _
        "KfU54KDFMBAGA1UdIAQJMAcwBQYDKgMEMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4IBAQArHQEorApwqumSn5EqDOAjbezi8fLco1cYES/PD+LQRM1Vb1g7VLE3hR4S5NNBv0bMwwWAr0WfL9lRRj0PMKLorO8y4TJjRU8MiYXfzSuKYL5Z16kW8zlVHw7CtmjhfjoIMwjQo3prifWxFv7VpfIBstKKShU0qB6KzUUNwg2O" & _
        "la4t4gg2JJcBmyIAIInHSGoeinR2V1tQ10aRqJdXkGin4WZ75yMbQH4L0NfotqY6bpF2CqIY3aogQyJGhUJji4gYnS2DvHcyoICwgawshjSaX8Y0Xlwnuh6EusqhqlhTgwPNAPrKIXCmOWtqjlDhho/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"
    n = SAT_CheckKeyAndCert(keyfile, password, certfile, 0)
    Debug.Print "SAT_CheckKeyAndCert(STRINGS)=" & n
    Call Our_Assert(n = 0, "SAT_CheckKeyAndCert failed")

    
    Debug.Print (vbLf & "GET RECEIPT (COMPROBANTE) VERSION NUMBER FROM XML FILE:")
    fname = "Muestra_v2_base2011.xml"
    n = SAT_XmlReceiptVersion(fname, 0)
    Debug.Print "SAT_XmlReceiptVersion(" & fname & ")=" & n
    Call Our_Assert(2 = n, "SAT_XmlReceiptVersion failed")
    fname = "ejemplo_v3_base2011.xml"
    n = SAT_XmlReceiptVersion(fname, 0)
    Debug.Print "SAT_XmlReceiptVersion(" & fname & ")=" & n
    Call Our_Assert(3 = n, "SAT_XmlReceiptVersion failed")
    ' New in v5.0
    fname = "Muestra_v22-base.xml"
    n = SAT_XmlReceiptVersion(fname, 0)
    Debug.Print "SAT_XmlReceiptVersion(" & fname & ")=" & n
    Call Our_Assert(22 = n, "SAT_XmlReceiptVersion failed")
    fname = "ejemplo_v32-base.xml"
    n = SAT_XmlReceiptVersion(fname, 0)
    Debug.Print "SAT_XmlReceiptVersion(" & fname & ")=" & n
    Call Our_Assert(32 = n, "SAT_XmlReceiptVersion failed")

    ' NEW IN [v4.0] ...
    
    ' Show we can now cope with CFDi XML with no prefixes...
    fname = "ejemplo_v3_noprefix.xml"
    n = SAT_XmlReceiptVersion(fname, 0)
    Debug.Print "SAT_XmlReceiptVersion(" & fname & ")=" & n
    Call Our_Assert(3 = n, "SAT_XmlReceiptVersion failed")

    Debug.Print (vbLf & "CREATE CADENA ORIGINAL DEL TIMBRE FISCAL DIGITAL (PIPESTRING FOR TFD):")
    fname = "ejemplo_v3_tfd.xml"
    s = tfdMakePipeStringFromXml(fname)
    Debug.Print "tfdMakePipeStringFromXml(" & fname & ")=" & vbCrLf & s
    
    Debug.Print (vbLf & "FORM DIGEST OF PIPESTRING FOR TFD:")
    fname = "ejemplo_v3_tfd.xml"
    s = tfdMakeDigestFromXml(fname)
    Debug.Print "tfdMakeDigestFromXml(" & fname & ")=" & vbCrLf & s
    Call Our_Assert(Len(s) > 0, "tfdMakeDigestFromXml failed")
    
    Debug.Print (vbLf & "EXTRACT DIGEST FROM TFD SELLOSAT:")
    certfile = "aaa010101aaa_CSD_02.cer"
    s1 = tfdExtractDigestFromSignature(fname, certfile)
    Debug.Print "tfdExtractDigestFromSignature(" & fname & ")=" & vbCrLf & s1
    Call Our_Assert(Len(s1) > 0, "tfdExtractDigestFromSignature failed")
    
    Call Our_Assert(StrComp(s1, s, vbTextCompare) = 0, "TFD Digests do not match")
    
    Debug.Print (vbLf & "PRETEND WE ARE A PAC WITH A KEY ALLOWED TO SIGN THE TFD:")
    fname = "ejemplo_v3_tfd.xml"
    keyfile = "aaa010101aaa_CSD_02.key"
    password = "a0123456789"
    s = tfdMakeSignatureFromXml(fname, keyfile, password)
    Debug.Print "tfdMakeSignatureFromXml(" & fname & ", " & keyfile & ")=" & vbCrLf & s
    Call Our_Assert(Len(s) > 0, "tfdMakeSignatureFromXml failed")
    ' Get the correct string from the TFD node
    s1 = satGetXmlAttribute(fname, "selloSAT", "TimbreFiscalDigital")
    Debug.Print "Correct=" & vbCrLf & s1
    
    Debug.Print (vbLf & "VERIFY SIGNATURE IN TFD SELLOSAT:")
    fname = "ejemplo_v3_tfd.xml"
    certfile = "aaa010101aaa_CSD_02.cer"
    n = tfdVerifySignature(fname, certfile)
    Debug.Print "tfdVerifySignature(" & fname & ", " & certfile & ")=" & n & " (expected 0)"
    Call Our_Assert(n = 0, "tfdVerifySignature failed")
    
    Call Our_Assert(StrComp(s1, s, vbTextCompare) = 0, "selloSATs do not match")
    
    ' NEW IN [v4.1] ...
    Debug.Print (vbLf & "ADD UTF-8 BOM TO EXISTING FILE:")
    fname = "Muestra_v2_signed2011.xml"
    newname = "Muestra_v2_with_BOM.xml"
    n = SAT_FixBOM(newname, fname, 0)
    Debug.Print "SAT_FixBOM(" & fname & "->" & newname & ")=" & n & " (expected 0)"
    Call Our_Assert(n = 0, "SAT_FixBOM failed")
    
    ' NEW IN [v5.0] ...
    Debug.Print (vbLf & "EXTRACT ATTRIBUTES FROM CONSECUTIVE ELEMENTS:")
    fname = "ejemplo_v3_base2011.xml"
    attributeName = "descripcion"
    elementName = "cfdi:Concepto"
    For i = 1 To 100
        eName = elementName & "[" & i & "]"
        s = satGetXmlAttribute(fname, attributeName, eName)
        Debug.Print "satGetXmlAttribute(" & attributeName & ", " & eName & ")='" & s & "'"
        If Len(s) = 0 Then
            Exit For
        End If
    Next
        
    Debug.Print (vbLf & "DETECT VERSION 2.2 OR 3.2 AUTOMATICALLY AND SIGN:")
    fname = "Muestra_v22-base.xml"
    newname = "Muestra_v22-new_signed.xml"
    keyfile = "aaa010101aaa_CSD_01.key"
    password = "a0123456789"
    certfile = "aaa010101aaa_CSD_01.cer"
    n = SAT_SignXml(newname, fname, keyfile, password, certfile, 0)
    Debug.Print "SAT_SignXml(" & fname & "->" & newname & ")=" & n & " (expected 0)"
    Call Our_Assert(n = 0, "SAT_SignXml failed")
    ' Did we make a valid XML file?
    n = SAT_ValidateXml(newname, 0)
    Debug.Print "SAT_ValidateXml returns " & n
    Call Our_Assert(n = 0, "SAT_ValidateXml failed")
    
    fname = "ejemplo_v32-base.xml"
    newname = "ejemplo_v32-new_signed.xml"
    keyfile = "aaa010101aaa_CSD_01.key"
    password = "a0123456789"
    certfile = "aaa010101aaa_CSD_01.cer"
    n = SAT_SignXml(newname, fname, keyfile, password, certfile, 0)
    Debug.Print "SAT_SignXml(" & fname & "->" & newname & ")=" & n & " (expected 0)"
    Call Our_Assert(n = 0, "SAT_SignXml failed")
    ' Did we make a valid XML file?
    n = SAT_ValidateXml(newname, 0)
    Debug.Print "SAT_ValidateXml returns " & n
    Call Our_Assert(n = 0, "SAT_ValidateXml failed")
   
    Debug.Print (vbLf & "VALIDATE XML WITH STRICT AND LOOSE OPTIONS:")
    fname = "V3_2_BadCurp.xml"
    Debug.Print "Default strict behaviour (badly formed CURP attribute)"
    n = SAT_ValidateXml(fname, 0)
    Debug.Print "SAT_ValidateXml('" & fname & "') returns " & n
    s = satLastError()
    Debug.Print "ErrorLookup(" & n & ")=" & satErrorLookup(n)
    Debug.Print "LastError=" & s
    Call Our_Assert(n <> 0, "SAT_ValidateXml failed to fail")
    
    Debug.Print "Using LOOSE option:"
    n = SAT_ValidateXml(fname, SAT_XML_LOOSE)
    Debug.Print "SAT_ValidateXml('" & fname & "', LOOSE) returns " & n
    Call Our_Assert(n = 0, "SAT_ValidateXml failed")
    
    Debug.Print (vbLf & "GET PRIVATE KEY AS BASE64:")
    fname = "aaa010101aaa_CSD_01.key"
    s = satGetKeyAsString(fname, "a0123456789")
    Debug.Print "GetCertAsString(" & fname & ")=" & vbLf & s
    Debug.Print "Len(satGetKeyAsString(" & fname & "))=" & Len(s)
    Call Our_Assert(Len(s) > 0, "satGetKeyAsString failed")
    
    Debug.Print (vbLf & "WRITE PFX FROM PRIVATE KEY AND CERT:")
    certfile = "aaa010101aaa_CSD_01.cer"
    keyfile = "aaa010101aaa_CSD_01.key"
    password = "a0123456789"
    fname = "archivo_pfx.pem"
    newpassword = "clavedesalida"
    n = SAT_WritePfxFile(fname, newpassword, keyfile, password, certfile, 0)
    Debug.Print "Sat.WritePfxFile()->" & fname & " returns " & n
    Call Our_Assert(n = 0, "Sat.WritePfxFile failed")
    Debug.Print "New PFX file is " & FileLen(fname) & " bytes long."
    
    Debug.Print (vbLf & "GET RFC AND ORG NAME FROM CERT:")
    fname = "aaa010101aaa_CSD_01.cer"
    Debug.Print "FILE: " & fname
    s = satQueryCert(fname, "rfc")
    Debug.Print "satQueryCert(rfc)="; s
    Call Our_Assert(Len(s) > 0, "satQueryCert(rfc) failed")
    s = satQueryCert(fname, "organizationName")
    Debug.Print "satQueryCert(organizationName)='" & s & "'"
    Call Our_Assert(Len(s) > 0, "satQueryCert(organizationName) failed")
    fname = "Muestra_v2_signed2011.xml"
    Debug.Print "FILE: " & fname
    s = satQueryCert(fname, "rfc")
    Debug.Print "satQueryCert(rfc)=" & s
    Call Our_Assert(Len(s) > 0, "satQueryCert(rfc) failed")
    s = satQueryCert(fname, "organizationName")
    Debug.Print "satQueryCert(organizationName)='" & s & "'"
    Call Our_Assert(Len(s) > 0, "satQueryCert(organizationName) failed")
    
    Debug.Print (vbLf & "TEST OTHER QUERIES FOR CERT:")
    fname = "aaa010101aaa_CSD_01.cer"
    Debug.Print "FILE: " & fname
    s = satQueryCert(fname, "notBefore")
    Debug.Print "satQueryCert(notBefore)=" & s
    Call Our_Assert(Len(s) > 0, "satQueryCert(notBefore) failed")
    s = satQueryCert(fname, "notAfter")
    Debug.Print "satQueryCert(notAfter)=" & s
    Call Our_Assert(Len(s) > 0, "satQueryCert(notAfter) failed")
    s = satQueryCert(fname, "serialNumber")
    Debug.Print "satQueryCert(serialNumber)=" & s
    Call Our_Assert(Len(s) > 0, "satQueryCert(serialNumber) failed")
    

    ' Finally, display version number...
    Debug.Print vbCrLf & "FirmaSAT Version=" & SAT_Version() & " [" & satCompileTime & "]"
    

' Change "#If 0" to "#If 1" to activate this
#If 0 Then
    Debug.Print (vbLf & "DISPLAY ALL POSSIBLE ERROR MESSAGES:");
    For i = 0 To 10000
        s = satErrorLookup(i)
       If Len(s) > 0 Then
            Debug.Print i & "=" & s
        End If
    Next i
#End If

End Sub

' *********************
' UTILITIES USED HERE *
' *********************

Public Function RequiredFilesExist() As Boolean
' Check for required files in current working directory
    Dim arrFiles As Variant
    Dim vnt As Variant
    
    arrFiles = Array( _
        "aaa010101aaa_CSD_01.cer", _
        "aaa010101aaa_CSD_01.key", _
        "aaa010101aaa_CSD_02.cer", _
        "aaa010101aaa_CSD_02.key", _
        "Muestra_v2_bad.xml", _
        "Muestra_v2_base2011.xml", _
        "Muestra_v2_signed2011.xml", _
        "detallista_base2011.xml", _
        "ejemplo_v3_base2011.xml", _
        "ejemplo_v3_tfd.xml", _
        "V2_2-base.xml", _
        "V3_2-base.xml", _
        "V3_2_BadCurp.xml", _
        "Muestra_v22-base.xml", _
        "ejemplo_v32-base.xml")
    For Each vnt In arrFiles
        If Not IsNormalFile(CStr(vnt)) Then
            Debug.Print "**ERROR: Cannot find file " & vnt
            Exit Function
        End If
    Next
    ' If we got here, all is OK
    RequiredFilesExist = True

End Function

Public Function IsNormalFile(sFileName As String) As Boolean
    Dim sDir As String
    If Len(sFileName) = 0 Then
        IsNormalFile = False
        Exit Function
    End If
    sDir = Dir(sFileName, vbNormal)
    IsNormalFile = (Len(sDir) > 0)
End Function

Public Sub Our_Assert(bState As Boolean, Optional strMsg As String)
    If bState = False Then
        If vbYes = MsgBox("ASSERT ERROR: " & strMsg & vbCrLf & "Stop the program?", vbCritical + vbYesNo, "ASSERT ERROR") Then
            Stop
        End If
    End If
End Sub