Imports System
Imports System.Diagnostics
Imports System.IO
Imports System.Text
Imports FirmaSAT
'
' * $Id: TestFirmaSat.vb $
' * Last updated:
' * $Date: 2020-08-05 17:01 $
' * $Version: 9.2.0 $
'
' Some tests using the FirmaSAT .NET interface.
' *
' * Requires `FirmaSAT` to be installed on your system: available from <https://cryptosys.net/firmasat/>.
' * Add a reference to `diFirmaSatNet.dll` installed in `C:\Program Files (x86)\FirmaSAT`.
' *
' * Test files are in `FirmaSATtestfiles.zip`. These must be in the CWD.
' *
' * This is a Console Application written for target .NET Framework 2.0 and above.
' * Please report any bugs to <https://cryptosys.net/contact>.
'
'****************************** LICENSE ***********************************
' * Copyright (C) 2010-20 David Ireland, DI Management Services Pty Limited.
' * All rights reserved. <https://di-mgt.com.au> <https://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>
'****************************************************************************
'
' [2020-07] Re-organised into modular form
' NOTE: Requires certain files to exist in the current working directory
' * (by default, the same directory as the executable).
' * See `arrFileNames` below - these files are in `FirmaSATtestfiles.zip`
'
' Ported from C# to VB.NET using icsharpcode.net's SharpDevelop.
Namespace TestFirmaSAT
''' <summary>
''' Test examples for FirmaSAT .NET interface
''' </summary>
Class TestFirmaSAT
Private Const MIN_FSA_VERSION As Integer = 90200
' Test files required to exist in the current working directory:
Private Shared arrFileNames As String() = New String() {"A7.xml", "AAA010101AAA201501BN-base.xml", "AAA010101AAA201501CT-base.xml", "AAA010101AAA201705CT.xml", "AC4_SAT.cer", "cfdv33a-base.xml", _
"cfdv33a-base-nocertnum.xml", "cfdv33a-bad-nover.xml", "cfdv33a-cce11-min.xml", "cfdv33a-cce11.xml", "cfdv33a-detallista-min.xml", "cfdv33a-detallista.xml", _
"cfdv33a-min.xml", "cfdv33a-nomina12.xml", "cfdv33a-nomina12B.xml", "cfdv33a-pagos10-min.xml", "cfdv33a-pagos10.xml", "cfdv33a-signed-tfd.xml", _
"cfdv33a-signed.xml", "contab-SelloDigitalContElec-signed.xml", "ConVolE12345-base.xml", "ConVolE12345-signed2015.xml", "CSD_E12345CV_ACP020530MP5.cer", "CSD_E12345CV_ACP020530MP5.key", _
"Ejemplo_Retenciones-base.xml", "Ejemplo_Retenciones-signed-tfd.xml", "ejemplo_v32-tfd2015.xml", "emisor-pem.cer", "emisor-pem.key", "emisor.cer", _
"emisor.key", "emisor1024.cer", "emisor1024.key", "pac.cer", "pac.key", "pac1024.cer", _
"pac1024.key", "V3_2_BadCurp.xml"}
''' <summary>
''' The main entry point for the application.
''' </summary>
<STAThread> _
Public Shared Sub Main(args As String())
' Make sure minimum required version of FirmaSAT is installed...
Console.WriteLine("FirmaSAT core Version is " & General.Version())
If General.Version() < MIN_FSA_VERSION Then
Console.WriteLine("FATAL ERROR: Require FirmaSAT core version " & MIN_FSA_VERSION & " or later.")
Return
End If
' CHECK FOR REQUIRED FILES IN CURRENT WORKING DIRECTORY
Console.WriteLine("Current working directory is {0}", Directory.GetCurrentDirectory())
Dim missingFile As String = "STOPPED: Required file is missing in current working directory"
For Each fn As String In arrFileNames
If FileIsNotPresent(fn, missingFile) Then
Return
End If
Next
' Handle command-line arguments
' * [some] just do some tests (default = do all)
'
Dim doSome As Boolean = False
For iarg As Integer = 0 To args.Length - 1
If args(iarg) = "some" Then
doSome = True
End If
Next
'*************
' DO THE TESTS
'*************
If doSome Then
' Use "some" in the command line
' Do some tests - comment these out as required
Console.WriteLine("Just doing some tests...")
'test_General();
'test_ErrorLookup();
'test_pipestring();
'test_SignAndVerify();
'test_Digest();
'test_Validate();
'test_ExtractAttribute();
'test_X509Certificate();
'test_MakeSignature();
'test_Detallista();
'test_CertValidity();
'test_CheckKeyAndCert();
'test_ReceiptVersion();
'test_Tfd();
'test_BOM();
'test_ExtractConsecutive();
'test_PrivateKey();
'test_QueryCert();
'test_SignInMemory();
'test_UUID();
'test_Retenciones();
'test_Contabilidad();
'test_ConVol();
'test_InsertCert();
'test_GetXmlAttribute_Advanced();
test_XMLasUnicodeString()
Else
' Do all the test modules (default)
Console.WriteLine("Doing all tests...")
DoAllTests()
End If
' ******************************************
' FINALLY, DISPLAY QUICK INFO ABOUT THE CORE DLL
Console.WriteLine(vbLf & "DETAILS OF CORE DLL...")
Console.WriteLine("DLL Version={0} [{1}] Lic={2} Compiled=[{3}] ", General.Version(), General.Platform(), General.LicenceType(), General.CompileTime())
Console.WriteLine("[{0}]", General.ModuleName())
'********************************************
Console.WriteLine(vbLf & "ALL TESTS COMPLETED.")
End Sub
Private Shared Sub DoAllTests()
test_General()
test_ErrorLookup()
test_pipestring()
test_SignAndVerify()
test_Digest()
test_Validate()
test_ExtractAttribute()
test_X509Certificate()
test_MakeSignature()
test_Detallista()
test_CertValidity()
test_CheckKeyAndCert()
test_ReceiptVersion()
test_Tfd()
test_BOM()
test_ConsecutiveElements()
test_PrivateKey()
test_QueryCert()
test_SignInMemory()
test_UUID()
test_Retenciones()
test_Contabilidad()
test_ConVol()
test_InsertCert()
test_GetXmlAttribute_Advanced()
test_XMLasUnicodeString()
End Sub
'********************
' THE TEST MODULES...
'********************
Private Shared Sub test_General()
Dim n As Integer
Dim ch As Char
Dim s As String
'****************
' GENERAL TESTS *
'****************
Console.WriteLine(vbLf & "INTERROGATE THE CORE DIFIRMASAT DLL:")
n = FirmaSAT.General.Version()
Console.WriteLine("Version={0}", n)
s = General.CompileTime()
Console.WriteLine("CompileTime={0}", s)
s = General.ModuleName()
Console.WriteLine("ModuleName={0}", s)
s = General.Platform()
Console.WriteLine("Platform={0}", s)
ch = General.LicenceType()
Console.WriteLine("LicenceType={0}", ch)
s = General.Comments()
Console.WriteLine("Comments={0}", s)
End Sub
Private Shared Sub test_ErrorLookup()
Dim s As String
'*****************
' ERROR LOOKUP TESTS *
'*********************
Console.WriteLine(vbLf & "ERROR CODES:")
For i As Integer = 0 To 9999
s = General.ErrorLookup(i)
If Not s.Equals([String].Empty) Then
Console.WriteLine("{0}={1}", i, s)
End If
Next
End Sub
Private Shared Sub test_pipestring()
Dim s As String
Dim fname As String
Console.WriteLine(vbLf & "FORM THE PIPESTRING FROM AN XML FILE:")
fname = "cfdv33a-base.xml"
s = Sat.MakePipeStringFromXml(fname)
Console.WriteLine("Sat.MakePipeStringFromXml('{0}')=" & vbLf & "{1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.MakePipeStringFromXml failed")
End Sub
Private Shared Sub test_SignAndVerify()
Dim n As Integer
Dim fname As String
Dim newname As String, keyfile As String, password As String, certfile As String
Console.WriteLine(vbLf & "SIGN AN XML FILE:")
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 = Sat.SignXml(newname, fname, keyfile, password, certfile)
Console.WriteLine("Sat.SignXml('{0}'-->'{1}') returns {2}", fname, newname, n)
Debug.Assert(n = 0, "Sat.SignXml failed")
' Did we make a valid XML file?
n = Sat.ValidateXml(newname)
Console.WriteLine("Sat.ValidateXml('{0}') returns {1}", newname, n)
Debug.Assert(n = 0, "Sat.ValidateXml failed")
Console.WriteLine(vbLf & "VERIFY A SIGNATURE IN AN XML FILE:")
Console.WriteLine("1. One we know is good:")
fname = "cfdv33a-signed-tfd.xml"
n = Sat.VerifySignature(fname)
Console.WriteLine("Sat.VerifySignature('{0}') returns {1}", fname, n)
Debug.Assert(n = 0, "Sat.VerifySignature failed")
Console.WriteLine("2. One we just made, so it should be good:")
fname = newname
n = Sat.VerifySignature(fname)
Console.WriteLine("Sat.VerifySignature('{0}') returns {1}", fname, n)
Debug.Assert(n = 0, "Sat.VerifySignature failed")
End Sub
Private Shared Sub test_Digest()
Dim s As String
Dim fname As String
Console.WriteLine(vbLf & "FORM THE DIGEST OF THE PIPESTRING IN AN XML FILE:")
fname = "cfdv33a-signed-tfd.xml"
s = Sat.MakeDigestFromXml(fname)
Console.WriteLine("Sat.MakeDigestFromXml('{0}')=" & vbLf & "{1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.MakeDigestFromXml failed")
Console.WriteLine(vbLf & "EXTRACT THE DIGEST FROM THE SIGNATURE IN AN XML FILE:")
fname = "cfdv33a-signed-tfd.xml"
s = Sat.ExtractDigestFromSignature(fname)
Console.WriteLine("Sat.ExtractDigestFromSignature('{0}')=" & vbLf & "{1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.ExtractDigestFromSignature failed")
End Sub
Private Shared Sub test_Validate()
Dim n As Integer
Dim s As String
Dim fname As String
Console.WriteLine(vbLf & "TRY VALIDATING XML FILES:")
Console.WriteLine("1. A valid one:")
fname = "cfdv33a-signed-tfd.xml"
n = Sat.ValidateXml(fname)
Console.WriteLine("Sat.ValidateXml('{0}') returns {1} (expecting 0)", fname, n)
Debug.Assert(n = 0, "Sat.ValidateXml failed")
Console.WriteLine("2. An invalid one (missing version):")
fname = "cfdv33a-bad-nover.xml"
n = Sat.ValidateXml(fname)
Console.WriteLine("Sat.ValidateXml('{0}') returns {1}", fname, n)
s = Sat.LastError()
Console.WriteLine("ErrorLookup({0})={1}", n, General.ErrorLookup(n))
Debug.Assert(n <> 0, "Sat.ValidateXml should have failed")
Console.WriteLine(vbLf & "VALIDATE XML WITH STRICT AND LOOSE OPTIONS:")
Console.WriteLine("Default strict behaviour (Bad attribute..@CURP..is too long):")
fname = "V3_2_BadCurp.xml"
n = Sat.ValidateXml(fname)
Console.WriteLine("Sat.ValidateXml('{0}') returns {1}", fname, n)
s = Sat.LastError()
Console.WriteLine("ErrorLookup({0})={1}", n, General.ErrorLookup(n))
Console.WriteLine("LastError={0}", s)
Debug.Assert(n <> 0, "Sat.ValidateXml failed to fail")
Console.WriteLine(vbLf & "Using XmlOption.Loose:")
n = Sat.ValidateXml(fname, XmlOption.Loose)
Console.WriteLine("Sat.ValidateXml('{0}', Loose) returns {1}", fname, n)
Debug.Assert(n = 0, "Sat.ValidateXml failed")
End Sub
Private Shared Sub test_ExtractAttribute()
Dim s As String
Dim fname As String
Dim attributeName As String, elementName As String
Console.WriteLine(vbLf & "EXTRACT AN ATTRIBUTE FROM AN XML FILE:")
fname = "cfdv33a-signed-tfd.xml"
elementName = "Comprobante"
attributeName = "Sello"
' NB capital 'S' for v3.3
s = Sat.GetXmlAttribute(fname, attributeName, elementName)
Console.WriteLine("Sat.GetXmlAttribute('{0}',{2},{3})=" & vbLf & "{1}", fname, s, attributeName, elementName)
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
elementName = "Comprobante"
attributeName = "Fecha"
s = Sat.GetXmlAttribute(fname, attributeName, elementName)
Console.WriteLine("Sat.GetXmlAttribute('{0}',{2},{3})=" & vbLf & "{1}", fname, s, attributeName, elementName)
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
Console.WriteLine(vbLf & "EXTRACT AN ATTRIBUTE WITH ACCENTED CHARACTERS:")
fname = "cfdv33a-base.xml"
elementName = "cfdi:Emisor"
attributeName = "Nombre"
s = Sat.GetXmlAttribute(fname, attributeName, elementName)
Console.WriteLine("Sat.GetXmlAttribute('{0}',{2},{3})={1}", fname, s, attributeName, elementName)
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
Console.WriteLine(vbLf & "EXTRACT AN ATTRIBUTE WITH ACCENTED CHARACTERS IN ITS NAME:")
fname = "cfdv33a-nomina12.xml"
elementName = "nomina12:CompensacionSaldosAFavor"
attributeName = "Año"
s = Sat.GetXmlAttribute(fname, attributeName, elementName)
Console.WriteLine("Sat.GetXmlAttribute('{0}',{2},{3})={1}", fname, s, attributeName, elementName)
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
End Sub
Private Shared Sub test_X509Certificate()
Dim s As String
Dim s1 As String
Dim fname As String
Console.WriteLine(vbLf & "GET DETAILS OF X.509 CERTIFICATE:")
Console.WriteLine("1. From embedded `certificado` in XML")
fname = "cfdv33a-signed-tfd.xml"
s = Sat.GetCertNumber(fname)
Console.WriteLine("Sat.GetCertNumber('{0}')={1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.GetCertNumber failed")
s = Sat.GetCertExpiry(fname)
Console.WriteLine("Sat.GetCertExpiry('{0}')={1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.GetCertExpiry failed")
Console.WriteLine("2. From X.509 file")
fname = "emisor.cer"
s = Sat.GetCertNumber(fname)
Console.WriteLine("Sat.GetCertNumber('{0}')={1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.GetCertNumber failed")
s = Sat.GetCertExpiry(fname)
Console.WriteLine("Sat.GetCertExpiry('{0}')={1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.GetCertExpiry failed")
Console.WriteLine(vbLf & "GET CERTIFICATE AS A BASE64 STRING:")
fname = "emisor.cer"
s = Sat.GetCertAsString(fname)
Console.WriteLine("Sat.GetCertAsString('{0}')=" & vbLf & "{1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.GetCertAsString failed")
Console.WriteLine("Sat.GetCertAsString('{0}').Length={1}", fname, s.Length)
' Compare against string from XML file
fname = "cfdv33a-signed-tfd.xml"
s1 = Sat.GetCertAsString(fname)
Console.WriteLine("Sat.GetCertAsString('{0}').Length={1}", fname, s1.Length)
Debug.Assert(s1.Length > 0, "Sat.GetCertAsString failed")
Debug.Assert([String].Compare(s, s1, True) = 0, "Sat.GetCertAsString failed")
End Sub
Private Shared Sub test_MakeSignature()
Dim s As String
Dim fname As String
Dim keyfile As String, password As String
Console.WriteLine(vbLf & "MAKE A SIGNATURE FROM A BASE XML FILE:")
fname = "cfdv33a-base.xml"
keyfile = "emisor.key"
password = "12345678a"
' CAUTION: DO NOT HARD-CODE REAL PASSWORDS!
s = Sat.MakeSignatureFromXml(fname, keyfile, password)
Console.WriteLine("Sat.MakeSignatureFromXml('{0}')=" & vbLf & "{1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.MakeSignatureFromXml failed")
End Sub
Private Shared Sub test_Detallista()
Dim n As Integer
Dim s As String
Dim fname As String
Dim keyfile As String, password As String
Dim newname As String, certfile As String
Dim attributeName As String, elementName As String
Console.WriteLine(vbLf & "SIGN A DETALLISTA XML FILE:")
fname = "cfdv33a-detallista.xml"
newname = "detallista_new-signed.xml"
keyfile = "emisor.key"
password = "12345678a"
' CAUTION: DO NOT HARD-CODE REAL PASSWORDS!
certfile = "emisor.cer"
n = Sat.SignXml(newname, fname, keyfile, password, certfile)
Console.WriteLine("Sat.SignXml('{0}'-->'{1}') returns {2}", fname, newname, n)
Debug.Assert(n = 0, "Sat.SignXml failed")
' Did we make a valid XML file?
n = Sat.ValidateXml(newname)
Console.WriteLine("Sat.ValidateXml('{0}') returns {1}", newname, n)
Debug.Assert(n = 0, "Sat.ValidateXml failed")
n = Sat.VerifySignature(newname)
Console.WriteLine("Sat.VerifySignature('{0}') returns {1}", newname, n)
Debug.Assert(n = 0, "Sat.VerifySignature failed")
Console.WriteLine(vbLf & "EXTRACT AN ATTRIBUTE FROM A DETALLISTA XML FILE:")
fname = "cfdv33a-detallista.xml"
elementName = "detallista:detallista"
attributeName = "documentStructureVersion"
s = Sat.GetXmlAttribute(fname, attributeName, elementName)
Console.WriteLine("Sat.GetXmlAttribute('{0}',{2},{3})={1}", fname, s, attributeName, elementName)
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
Debug.Assert([String].Compare(s, "AMC8.1") = 0, "Invalid detallista.documentStructureVersion")
End Sub
Private Shared Sub test_CertValidity()
Dim s As String
Dim fname As String
Console.WriteLine(vbLf & "GET VALIDITY DETAILS OF X.509 CERTIFICATE:")
Console.WriteLine("1. From embedded `certificado` in XML")
fname = "cfdv33a-signed-tfd.xml"
s = Sat.GetCertExpiry(fname)
Console.WriteLine("Sat.GetCertExpiry('{0}')=" & vbTab & "{1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.GetCertExpiry failed")
s = Sat.GetCertStart(fname)
Console.WriteLine("Sat.GetCertStart('{0}') =" & vbTab & "{1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.GetCertStart failed")
Console.WriteLine("2. From X.509 file")
fname = "emisor.cer"
s = Sat.GetCertExpiry(fname)
Console.WriteLine("Sat.GetCertExpiry('{0}')=" & vbTab & "{1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.GetCertExpiry failed")
s = Sat.GetCertStart(fname)
Console.WriteLine("Sat.GetCertStart('{0}') =" & vbTab & "{1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.GetCertStart failed")
End Sub
Private Shared Sub test_CheckKeyAndCert()
Dim n As Integer
Dim keyfile As String, password As String, certfile As String
Console.WriteLine(vbLf & "CHECK PRIVATE KEY MATCHES PUBLIC KEY IN CERTIFICATE:")
certfile = "emisor.cer"
keyfile = "emisor.key"
password = "12345678a"
' CAUTION: DO NOT HARD-CODE REAL PASSWORDS!
n = Sat.CheckKeyAndCert(keyfile, password, certfile)
Console.WriteLine("Sat.CheckKeyAndCert({0},{1}) = {2}", keyfile, certfile, n)
Debug.Assert(n = 0, "Sat.CheckKeyAndCert failed")
certfile = "pac.cer"
keyfile = "pac.key"
password = "12345678a"
n = Sat.CheckKeyAndCert(keyfile, password, certfile)
Console.WriteLine("Sat.CheckKeyAndCert({0},{1}) = {2}", keyfile, certfile, n)
Debug.Assert(n = 0, "Sat.CheckKeyAndCert failed")
' Get embedded certificate from XML doc
certfile = "cfdv33a-signed-tfd.xml"
keyfile = "emisor.key"
password = "12345678a"
n = Sat.CheckKeyAndCert(keyfile, password, certfile)
Console.WriteLine("Sat.CheckKeyAndCert({0},{1}) = {2}", keyfile, certfile, n)
Debug.Assert(n = 0, "Sat.CheckKeyAndCert failed")
End Sub
Private Shared Sub test_ReceiptVersion()
Dim n As Integer
Dim fname As String
Console.WriteLine(vbLf & "FIND THE COMPROBANTE VERSION OF AN XML FILE:")
fname = "cfdv33a-base.xml."
n = Sat.XmlReceiptVersion(fname)
Console.WriteLine("Sat.XmlReceiptVersion('{0}') = {1}", fname, n)
Debug.Assert(n = 33, "Sat.XmlReceiptVersion failed")
' Older version...
Console.WriteLine("Legacy versions still work...")
fname = "ejemplo_v32-tfd2015.xml"
n = Sat.XmlReceiptVersion(fname)
Console.WriteLine("Sat.XmlReceiptVersion('{0}') = {1}", fname, n)
Debug.Assert(n = 32, "Sat.XmlReceiptVersion failed")
End Sub
Private Shared Sub test_Tfd()
Dim n As Integer
Dim s As String
Dim fname As String
Dim newname As String, keyfile As String, password As String, certfile As String
Dim s1 As String
Console.WriteLine(vbLf & "CREATE CADENA ORIGINAL DEL TIMBRE FISCAL DIGITAL (PIPESTRING FOR TFD):")
fname = "cfdv33a-signed-tfd.xml"
certfile = "pac.cer"
s = Tfd.MakePipeStringFromXml(fname)
Console.WriteLine("Tfd.MakePipeStringFromXml('{0}') =" & vbLf & "{1}", fname, s)
Console.WriteLine(vbLf & "FORM DIGEST OF PIPESTRING FOR TFD:")
s = Tfd.MakeDigestFromXml(fname)
Console.WriteLine("Tfd.MakeDigestFromXml('{0}')=" & vbLf & "{1}", fname, s)
Console.WriteLine(vbLf & "EXTRACT DIGEST FROM TFD SELLOSAT:")
' NB certFile is required for Tfd
s1 = Tfd.ExtractDigestFromSignature(fname, certfile)
Console.WriteLine("Tfd.ExtractDigestFromSignature('{0}')=" & vbLf & "{1}", fname, s1)
' Check the two digests match
Debug.Assert([String].Compare(s, s1, True) = 0, "Digests do not match")
Console.WriteLine(vbLf & "PRETEND WE ARE A PAC WITH A KEY ALLOWED TO SIGN THE TFD:")
' Pretend we are a PAC with a key allowed to sign the TFD
' so create a TFD signature string we could paste into the `selloSAT' node
fname = "cfdv33a-signed-tfd.xml"
certfile = "pac.cer"
keyfile = "pac.key"
password = "12345678a"
s = Tfd.MakeSignatureFromXml(fname, keyfile, password)
Console.WriteLine("Tfd.MakeSignatureFromXml('{0}')=" & vbLf & "{1}", fname, s)
s1 = Sat.GetXmlAttribute(fname, "SelloSAT", "TimbreFiscalDigital")
' NB Capital 'S' in Sello for TFD v1.1
Console.WriteLine("Correct=" & vbLf & "{0}", s1)
Debug.Assert([String].Compare(s, s1, True) = 0, "selloSAT values do not match")
Console.WriteLine(vbLf & "ADD A TFD ELEMENT TO A SIGNED CFDI DOCUMENT USING PAC KEY:")
fname = "cfdv33a-signed.xml"
newname = "cfdv33a_new-tfd.xml"
certfile = "pac.cer"
keyfile = "pac.key"
password = "12345678a"
n = Tfd.AddSignedTfd(newname, fname, keyfile, password, certfile)
Console.WriteLine("Tfd.AddSignedTfd('{0}') returns {1} (expected 0)" & vbLf, newname, n)
Debug.Assert(0 = n, "Tfd.AddSignedTfd failed")
' Did we make a valid XML file?
n = Sat.ValidateXml(newname)
Console.WriteLine("Sat.ValidateXml('{0}') returns {1} (expected 0)" & vbLf, newname, n)
Debug.Assert(0 = n, "Sat.ValidateXml failed")
Console.WriteLine(vbLf & "VERIFY SIGNATURE IN TFD SELLOSAT:")
n = Tfd.VerifySignature(newname, certfile)
Console.WriteLine("Tfd.VerifySignature({0},{1})={2} (expected 0)", newname, certfile, n)
Debug.Assert(n = 0, "Tfd.VerifySignature failed")
End Sub
Private Shared Sub test_BOM()
Dim n As Integer
Dim fname As String
Dim newname As String
Console.WriteLine(vbLf & "ADD UTF-8 BOM TO EXISTING FILE:")
fname = "cfdv33a-signed-nobom.xml"
Console.WriteLine("FileHasBom('{0}')={1} ", fname, FileHasBom(fname))
newname = "cfdv33a_new-signed-with-BOM.xml"
n = Sat.FixBom(newname, fname)
Console.WriteLine("Sat.FixBom({0}->{1})={2} (expected 0)", fname, newname, n)
Debug.Assert(n = 0, "Sat.FixBom failed")
Console.WriteLine("FileHasBom('{0}')={1} ", newname, FileHasBom(newname))
End Sub
Private Shared Sub test_ConsecutiveElements()
Dim s As String
Dim fname As String
Dim attributeName As String, elementName As String
Console.WriteLine(vbLf & "EXTRACT ATTRIBUTES FROM CONSECUTIVE ELEMENTS:")
fname = "ejemplo_v32-tfd2015.xml"
attributeName = "descripcion"
elementName = "cfdi:Concepto"
Console.WriteLine("For file '{0}'", fname)
Dim eName As String = Nothing
For i As Integer = 1 To 10
eName = elementName & String.Format("[{0:d}]", i)
Console.Write("Sat.GetXmlAttribute({0},{1})=", attributeName, eName)
s = Sat.GetXmlAttribute(fname, attributeName, eName)
If Sat.XmlNoMatch() = s Then
' [2020-07-06] Changed from empty string
Exit For
End If
Console.WriteLine("{0}", s)
Next
Console.WriteLine()
End Sub
Private Shared Sub test_PrivateKey()
Dim n As Integer
Dim s As String
Dim fname As String
Dim keyfile As String, password As String, certfile As String
Dim newname As String
Dim newpassword As String
Console.WriteLine(vbLf & "GET PRIVATE KEY AS BASE64:")
fname = "emisor.key"
password = "12345678a"
s = Sat.GetKeyAsString(fname, password)
Console.WriteLine("Sat.GetKeyAsString({0})=" & vbLf & "{1}" & vbLf, fname, s)
Console.WriteLine("Sat.GetKeyAsString('{0}').Length={1}", fname, s.Length)
Debug.Assert(s.Length > 0, "Sat.GetKeyAsString failed")
Console.WriteLine(vbLf & "WRITE PFX FROM PRIVATE KEY AND CERT:")
certfile = "emisor.cer"
keyfile = "emisor.key"
password = "12345678a"
fname = "archivo_new-pfx.txt"
newpassword = "clavedesalida"
n = Sat.WritePfxFile(fname, newpassword, keyfile, password, certfile)
Console.WriteLine("Sat.WritePfxFile()->{0} returns {1}", fname, n)
Debug.Assert(n = 0, "Sat.WritePfxFile failed")
Console.WriteLine("New PFX file is {0} bytes long.", FileLength(fname))
Console.WriteLine(vbLf & "SAVE KEYFILE WITH NEW PASSWORD...")
keyfile = "emisor.key"
password = "12345678a"
newname = "emisor_new.key"
newpassword = "password123"
n = Sat.NewKeyFile(newname, newpassword, keyfile, password, 0)
Console.WriteLine("Sat.NewKeyFile() returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Sat.NewKeyFile failed")
Console.WriteLine("Created new key file '{0}' of length {1} bytes with password '{2}'.", newname, FileLength(newname), newpassword)
Console.WriteLine("Save again in PEM format...")
newname = "emisor_new.pem"
newpassword = "password456"
n = Sat.NewKeyFile(newname, newpassword, keyfile, password, KeyFormat.PEM)
Console.WriteLine("Sat.NewKeyFile(KeyFormat.PEM) returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Sat.NewKeyFile failed")
Console.WriteLine("Created new key file '{0}' of length {1} bytes with password '{2}'.", newname, FileLength(newname), newpassword)
End Sub
Private Shared Sub test_QueryCert()
Dim s As String
Dim fname As String
Console.WriteLine(vbLf & "GET RFC AND ORG NAME FROM CERT:")
fname = "emisor.cer"
Console.WriteLine("FILE: {0}", fname)
s = Sat.QueryCert(fname, Query.rfc)
Console.WriteLine("Sat.QueryCert(rfc)={0}", s)
Debug.Assert(s.Length > 0, "Sat.QueryCert(rfc) failed")
s = Sat.QueryCert(fname, Query.organizationName)
Console.WriteLine("Sat.QueryCert(organizationName)='{0}'", s)
Debug.Assert(s.Length > 0, "Sat.QueryCert(organizationName) failed")
fname = "cfdv33a-signed-tfd.xml"
Console.WriteLine("FILE: {0}", fname)
s = Sat.QueryCert(fname, Query.rfc)
Console.WriteLine("Sat.QueryCert(rfc)={0}", s)
Debug.Assert(s.Length > 0, "Sat.QueryCert(rfc) failed")
s = Sat.QueryCert(fname, Query.organizationName)
Console.WriteLine("Sat.QueryCert(organizationName)='{0}'", s)
Debug.Assert(s.Length > 0, "Sat.QueryCert(organizationName) failed")
Console.WriteLine(vbLf & "TEST OTHER QUERIES FOR CERT:")
fname = "emisor.cer"
Console.WriteLine("FILE: {0}", fname)
s = Sat.QueryCert(fname, Query.notBefore)
Console.WriteLine("Sat.QueryCert(notBefore)={0}", s)
Debug.Assert(s.Length > 0, "Sat.QueryCert(notBefore) failed")
s = Sat.QueryCert(fname, Query.notAfter)
Console.WriteLine("Sat.QueryCert(notAfter)={0}", s)
Debug.Assert(s.Length > 0, "Sat.QueryCert(notAfter) failed")
s = Sat.QueryCert(fname, Query.serialNumber)
Console.WriteLine("Sat.QueryCert(serialNumber)={0}", s)
Debug.Assert(s.Length > 0, "Sat.QueryCert(serialNumber) failed")
Console.WriteLine(vbLf & "QUERY KEY SIZE OF CERTIFICATES...")
fname = "emisor1024.cer"
s = Sat.QueryCert(fname, Query.keySize)
Console.WriteLine("Sat.QueryCert('{0}',keySize)={1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.QueryCert(keySize) failed")
fname = "emisor.cer"
s = Sat.QueryCert(fname, Query.keySize)
Console.WriteLine("Sat.QueryCert('{0}',keySize)={1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.QueryCert(keySize) failed")
fname = "AC4_SAT.cer"
s = Sat.QueryCert(fname, Query.keySize)
Console.WriteLine("Sat.QueryCert('{0}',keySize)={1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.QueryCert(keySize) failed")
Console.WriteLine(vbLf & "QUERY SIGNATURE ALGORITHM IN CERTIFICATES...")
fname = "emisor1024.cer"
s = Sat.QueryCert(fname, Query.sigAlg)
Console.WriteLine("Sat.QueryCert('{0}',sigAlg)={1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.QueryCert(sigAlg) failed")
fname = "emisor.cer"
s = Sat.QueryCert(fname, Query.sigAlg)
Console.WriteLine("Sat.QueryCert('{0}',sigAlg)={1}", fname, s)
Debug.Assert(s.Length > 0, "Sat.QueryCert(sigAlg) failed")
End Sub
Private Shared Sub test_SignInMemory()
Dim n As Integer
Dim fname As String
Dim keyfile As String, password As String, certfile As String
Dim xmlArr As Byte()
Dim b As Byte()
Console.WriteLine(vbLf & "SIGN XML FROM BYTES TO BYTES:")
' 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.
' These strings are from `emisor-pem.cer` and `emisor-pem.key`, respectively
certfile = "-----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-----"
keyfile = "-----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 matches certificate
n = Sat.CheckKeyAndCert(keyfile, password, certfile)
Console.WriteLine("Sat.CheckKeyAndCert(STRINGS) = {0}", n)
Debug.Assert(n = 0, "Sat.CheckKeyAndCert failed")
' Read in a UTF-8-encoded XML file into a byte array
fname = "cfdv33a-base.xml"
xmlArr = File.ReadAllBytes(fname)
Console.WriteLine("File '{0}'-->{1} UTF-8 bytes", fname, xmlArr.Length)
Dim s1 As String = ""
Dim s2 As String = ""
' Sign it and receive result back as a byte array...
b = Sat.SignXmlToBytes(xmlArr, keyfile, password, certfile, 0)
If b.Length = 0 Then
Console.WriteLine("ERROR={0}", General.LastError())
Else
' Convert this to a string
s1 = System.Text.Encoding.UTF8.GetString(b)
Console.WriteLine("XML-OUT=" & vbLf & "---" & vbLf & "{0}" & vbLf & "---" & vbLf, s1)
Console.WriteLine("From bytes: XML-OUT: {0} bytes --> {1} chars", b.Length, s1.Length)
End If
' Sign the file instead and receive result back as a byte array...
b = Sat.SignXmlToBytes(fname, keyfile, password, certfile, 0)
If b.Length = 0 Then
Console.WriteLine("ERROR={0}", General.LastError())
Else
' Convert this to a string
s2 = System.Text.Encoding.UTF8.GetString(b)
Console.WriteLine("From file: XML-OUT: {0} bytes --> {1} chars", b.Length, s2.Length)
Debug.Assert(s1.Equals(s2))
End If
End Sub
Private Shared Sub test_UUID()
Dim s As String
Console.WriteLine(vbLf & "GENERATE 3 UUIDs:")
s = Sat.Uuid()
Console.WriteLine("UUID={0}", s)
s = Sat.Uuid()
Console.WriteLine("UUID={0}", s)
s = Sat.Uuid()
Console.WriteLine("UUID={0}", s)
End Sub
Private Shared Sub test_Retenciones()
Dim n As Integer
Dim s As String
Dim fname As String
Console.WriteLine(vbLf & "WORK WITH A `RETENCIONES` DOCUMENT:")
fname = "Ejemplo_Retenciones-base.xml"
Console.WriteLine("FILE={0}", fname)
n = Sat.XmlReceiptVersion(fname)
Console.WriteLine("Sat.XmlReceiptVersion() returns ID={0} (expecting 1010)", n)
Debug.Assert(1010 = n, "Sat.XmlReceiptVersion failed")
s = Sat.MakeDigestFromXml(fname)
Console.WriteLine("Sat.MakeDigestFromXml() -> {0}", s)
Debug.Assert(s.Length > 0, "Sat.MakeDigestFromXml failed")
' Use new [v6.0] option to find name of root element
s = Sat.GetXmlAttribute(fname, "", "")
Console.WriteLine("File root element is '{0}'", s)
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute('','') failed")
End Sub
Private Shared Sub test_Contabilidad()
Dim n As Integer
Dim s As String
Dim fname As String
Dim newname As String, keyfile As String, password As String, certfile As String
Console.WriteLine(vbLf & "WORK WITH `CONTABILIDAD` DOCUMENTS:")
fname = "AAA010101AAA201501CT-base.xml"
Console.WriteLine("CATALOGOCUENTAS FILE={0}", fname)
n = Sat.XmlReceiptVersion(fname)
Console.WriteLine("Sat.XmlReceiptVersion() returns ID={0} (expecting 2011)", n)
Debug.Assert(2011 = n, "Sat.XmlReceiptVersion failed")
Console.WriteLine("SIGN A CATALOGOCUENTAS DOCUMENT...")
newname = "AAA010101AAA201501CT_new-signed.xml"
keyfile = "emisor.key"
certfile = "emisor.cer"
password = "12345678a"
n = Sat.SignXml(newname, fname, keyfile, password, certfile)
Console.WriteLine("Sat.SignXml() returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Sat.SignXml failed")
n = Sat.VerifySignature(newname)
Console.WriteLine("Sat.VerifySignature() returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Sat.VerifySignature failed")
fname = "AAA010101AAA201501BN-base.xml"
Console.WriteLine("BALANZA FILE={0}", fname)
n = Sat.XmlReceiptVersion(fname)
Console.WriteLine("Sat.XmlReceiptVersion() returns ID={0} (expecting 2111)", n)
Debug.Assert(2111 = n, "Sat.XmlReceiptVersion failed")
Console.WriteLine("MAKE THE SIGNATURE STRING FOR BALANZA...")
s = Sat.MakeSignatureFromXml(fname, keyfile, password)
Console.WriteLine("Sat.MakeSignatureFromXml() ->" & vbLf & "{0}", s)
Debug.Assert(s.Length > 0, "Sat.MakeSignatureFromXml() failed")
fname = "contab-SelloDigitalContElec-signed.xml"
Console.WriteLine("SELLODIGITALCONTELEC FILE={0}", fname)
n = Sat.XmlReceiptVersion(fname)
Console.WriteLine("Sat.XmlReceiptVersion() returns ID={0} (expecting 2511)", n)
Debug.Assert(2511 = n, "Sat.XmlReceiptVersion failed")
Console.WriteLine("VERIFY SIGNATURE FOR SELLODIGITALCONTELEC USING PAC CERTIFICATE...")
n = Sat.VerifySignature(fname, "pac1024.cer")
Console.WriteLine("Sat.VerifySignature() returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Sat.VerifySignature failed")
' NEW IN [v8.1]
Console.WriteLine(vbLf & "SUPPORT FOR CONTABILIDAD V1.3...")
fname = "AAA010101AAA201705CT.xml"
Console.WriteLine("FILE: {0}", fname)
s = Sat.GetXmlAttribute(fname, "", "")
Console.WriteLine("Doc type is '{1}'", fname, s)
n = Sat.ValidateXml(fname)
Console.WriteLine("Sat.ValidateXml() returns {0} (0 => OK)", n)
Debug.Assert(0 = n, "Sat.ValidateXml failed")
n = Sat.VerifySignature(fname)
Console.WriteLine("Sat.VerifySignature() returns {0} (0 => OK)", n)
Debug.Assert(0 = n, "Sat.VerifySignature failed")
n = Sat.XmlReceiptVersion(fname)
Console.WriteLine("Sat.XmlReceiptVersion() returns {0} (expecting 2013)", n)
s = Sat.DefaultDigestAlg(fname)
Console.WriteLine("Default digest algorithm is '{0}'", s)
End Sub
Private Shared Sub test_ConVol()
Dim n As Integer
Dim fname As String
Dim newname As String, keyfile As String, password As String, certfile As String
Console.WriteLine(vbLf & "WORK WITH `CONTROLESVOLUMETRICOS` DOCUMENT:")
fname = "ConVolE12345-base.xml"
Console.WriteLine("FILE={0}", fname)
n = Sat.XmlReceiptVersion(fname)
Console.WriteLine("Sat.XmlReceiptVersion() returns ID={0} (expecting 4011)", n)
Debug.Assert(4011 = n, "Sat.XmlReceiptVersion failed")
Console.WriteLine("SIGN A CONVOL DOCUMENT WITH BIGFILE FLAG...")
newname = "ConVolE12345_new-signed.xml"
' Use key and cert provided for ConVol tests
keyfile = "CSD_E12345CV_ACP020530MP5.key"
certfile = "CSD_E12345CV_ACP020530MP5.cer"
password = "12345678a"
n = Sat.SignXmlEx(newname, fname, keyfile, password, certfile, SignOptions.BigFile)
Console.WriteLine("Sat.SignXmlEx(BigFile) returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Sat.SignXmlEx(BigFile) failed")
n = Sat.VerifySignature(newname)
Console.WriteLine("Sat.VerifySignature() returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Sat.VerifySignature failed")
End Sub
Private Shared Sub test_InsertCert()
Dim n As Integer
Dim s As String
Dim fname As String
Dim newname As String, password As String, certfile As String
Dim cerStr As String
Dim xmlStr As String
Dim keyStr As String
Dim newStr As String
Dim b As Byte()
Console.WriteLine(vbLf & "INSERT CERTIFICATE INTO XML...")
' Take an XML file without a Nocertificado...
fname = "cfdv33a-base-nocertnum.xml"
Console.WriteLine("Start file '{0}'.NoCertificado=[{1}]", fname, Sat.GetXmlAttribute(fname, "NoCertificado", "cfdi:Comprobante"))
Console.WriteLine("Start file '{0}'.Certificado={1} bytes", fname, Sat.GetXmlAttribute(fname, "Certificado", "cfdi:Comprobante").Length)
' Insert certificate details...
certfile = "emisor.cer"
newname = "cfdv33a_new-base-pluscert.xml"
n = Sat.InsertCert(newname, fname, certfile)
Console.WriteLine("Sat.InsertCert() returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Sat.InsertCert failed")
fname = newname
Console.WriteLine("Inter file '{0}'.NoCertificado=[{1}]", fname, Sat.GetXmlAttribute(fname, "NoCertificado", "cfdi:Comprobante"))
Console.WriteLine("Inter file '{0}'.Certificado={1} bytes", fname, Sat.GetXmlAttribute(fname, "Certificado", "cfdi:Comprobante").Length)
' Sign it - no need to specify the certificate
newname = "cfdv33a_new-signed-pluscert.xml"
n = Sat.SignXml(newname, fname, "emisor.key", "12345678a", Nothing)
Console.WriteLine("Sat.SignXml() returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Sat.SignXml failed")
' Verify that it worked
n = Sat.VerifySignature(newname)
Console.WriteLine("Sat.VerifySignature() returns {0} (0 => OK)", n)
Debug.Assert(0 = n, "Sat.VerifySignature failed")
Console.WriteLine(vbLf & "INSERT CERTIFICATE INTO XML USING STRINGS ONLY...")
' Read in data to strings
password = "12345678a"
xmlStr = File.ReadAllText("cfdv33a-base-nocertnum.xml")
cerStr = Sat.GetCertAsString("emisor.cer")
keyStr = Sat.GetKeyAsString("emisor.key", password, KeyOption.EncryptedPEM)
Console.WriteLine("String lengths: XML={0}, CER={1}, KEY={2}", xmlStr.Length, cerStr.Length, keyStr.Length)
' Show we can use just strings
n = Sat.CheckKeyAndCert(keyStr, password, cerStr)
Console.WriteLine("Sat.CheckKeyAndCert() returns {0} (0 => OK)", n)
s = Sat.GetXmlAttribute(xmlStr, "Moneda", "cfdi:Comprobante")
Console.WriteLine("Moneda in XML=[{0}]", s)
' Insert certificate details. Note (string) -> (bytes) -> (string)
b = Sat.InsertCertToBytes(xmlStr, cerStr)
Console.WriteLine("Sat.InsertCertToBytes() returns byte array of length {0}", b.Length)
If b.Length = 0 Then
DisplayError()
End If
Debug.Assert(b.Length > 0)
newStr = System.Text.Encoding.UTF8.GetString(b)
Console.WriteLine("XML string has length {0}", newStr.Length)
' Check we have a NoCertificado attribute...
s = Sat.GetXmlAttribute(newStr, "NoCertificado", "cfdi:Comprobante")
Console.WriteLine("NoCertificado=[{0}]", s)
If s.Length = 0 Then
DisplayError()
End If
xmlStr = newStr
' Sign it - all strings, no cert required
newStr = System.Text.Encoding.UTF8.GetString(Sat.SignXmlToBytes(xmlStr, keyStr, password, Nothing, 0))
' Verify that it worked
n = Sat.VerifySignature(newStr)
Console.WriteLine("Sat.VerifySignature() returns {0} (0 => OK)", n)
If n <> 0 Then
DisplayError(n)
End If
Debug.Assert(0 = n, "Sat.VerifySignature failed")
End Sub
Private Shared Sub test_GetXmlAttribute_Advanced()
Dim s As String
Dim fname As String
Dim attributeName As String, elementName As String
Dim xbase As String, xpath As String, val As String
Dim i As Integer, j As Integer
Console.WriteLine(vbLf & "XPATH EXPRESSIONS FOR XMLGETATTRIBUTE...")
fname = "A7.xml"
Console.WriteLine("FILE: {0}", fname)
elementName = "/Comprobante"
attributeName = "Version"
s = Sat.GetXmlAttribute(fname, attributeName, elementName)
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
Console.WriteLine("elemname='{0}' attributeName='{1}' attrValue='{2}'", elementName, attributeName, s)
elementName = "/Comprobante/Conceptos/Concepto[2]/Impuestos/Traslados/Traslado[1]"
attributeName = "Importe"
s = Sat.GetXmlAttribute(fname, attributeName, elementName)
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
Console.WriteLine("elemname='{0}' attributeName='{1}' attrValue='{2}'", elementName, attributeName, s)
elementName = "/Comprobante/Conceptos/Concepto[1]/Impuestos/Retenciones/Retencion[2]"
attributeName = "Importe"
s = Sat.GetXmlAttribute(fname, attributeName, elementName)
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
Console.WriteLine("elemname='{0}' attributeName='{1}' attrValue='{2}'", elementName, attributeName, s)
' Same as above but shorter
elementName = "//Conceptos/Concepto[1]//Retencion[2]"
attributeName = "Importe"
s = Sat.GetXmlAttribute(fname, attributeName, elementName)
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
Console.WriteLine("elemname='{0}' attributeName='{1}' attrValue='{2}'", elementName, attributeName, s)
' Test for existence
Console.WriteLine("Check for existence...")
elementName = "/Comprobante/Conceptos/Concepto[3]"
attributeName = "Importe"
s = Sat.GetXmlAttribute(fname, attributeName, elementName)
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
Console.WriteLine("elemname='{0}' attributeName='{1}' attrValue='{2}'", elementName, attributeName, s)
Console.WriteLine("Loop through all Concepto elements until no match...")
i = 1
While True
elementName = "//Conceptos/Concepto" & "[" & i & "]"
s = Sat.GetXmlAttribute(fname, attributeName, elementName)
Console.WriteLine("elemname='{0}' attributeName='{1}' attrValue='{2}'", elementName, attributeName, s)
If Sat.XmlNoMatch() = s Then
Exit While
End If
i += 1
End While
Console.WriteLine("Invalid path expression...")
elementName = "/"
attributeName = "Version"
Console.WriteLine("elemname='{0}' attributeName='{1}'", elementName, attributeName)
s = Sat.GetXmlAttribute(fname, attributeName, elementName)
If s.Length = 0 Then
Console.WriteLine("ERROR={0}", General.LastError())
End If
Debug.Assert(s.Length = 0, "Sat.GetXmlAttribute failed")
Console.WriteLine(vbLf & "ADVANCED XMLGETATTRIBUTE 'NOMATCH' FEATURES...")
s = Sat.XmlNoMatch()
Console.WriteLine("Sat.XmlNoMatch() returns '{0}'", s)
Console.WriteLine("Set a new value to be returned...")
Sat.SetXmlNoMatch("##No coinciden##")
s = Sat.XmlNoMatch()
Console.WriteLine("Sat.XmlNoMatch() returns '{0}'", s)
fname = "cfdv33a-signed-tfd.xml"
Console.WriteLine("FILE: {0}", fname)
elementName = "/Comprobante/notthere"
s = Sat.GetXmlAttribute(fname, "", elementName)
Console.WriteLine("Sat.GetXmlAttribute({0}) returns '{1}'", elementName, s)
elementName = "/Comprobante/Impuestos"
s = Sat.GetXmlAttribute(fname, "", elementName)
Console.WriteLine("Sat.GetXmlAttribute({0}) returns '{1}'", elementName, s)
Console.WriteLine(vbLf & "USE XPATH TO FIND ALL ATTRIBUTES NAMED 'IMPORTE'...")
fname = "A7.xml"
Console.WriteLine("FILE: {0}", fname)
' Output all attributes named "Importe" in a <Traslado> or <Retencion> element.
attributeName = "Importe"
' First look at each <Concepto> in the <Conceptos> element.
' (We can use either "/Comprobante/Conceptos" or "//Conceptos")
xbase = "//Conceptos/Concepto"
i = 1
While True
' FOREACH //Conceptos/Concepto[i] element output the value of Importe
xpath = xbase & "[" & i & "]"
val = Sat.GetXmlAttribute(fname, attributeName, xpath)
If Sat.XmlNoMatch() = val Then
Exit While
End If
Console.WriteLine("{0}/@{1}='{2}'", xpath, attributeName, val)
' FOREACH //Conceptos/Concepto[i]//Traslado[j] element output the value of Importe
' Long xpath is /Comprobante/Conceptos/Concepto[i]/Impuestos/Traslados/Traslado[j]
j = 1
While True
Dim xpath1 As String = xpath & "//Traslado[" & j & "]"
val = Sat.GetXmlAttribute(fname, attributeName, xpath1)
If Sat.XmlNoMatch() = val Then
Exit While
End If
Console.WriteLine("{0}/@{1}='{2}'", xpath1, attributeName, val)
j += 1
End While
' FOREACH //Conceptos/Concepto[i]//Retencion[j] element output the value of Importe
j = 1
While True
Dim xpath1 As String = xpath & "//Retencion[" & j & "]"
val = Sat.GetXmlAttribute(fname, attributeName, xpath1)
If Sat.XmlNoMatch() = val Then
Exit While
End If
Console.WriteLine("{0}/@{1}='{2}'", xpath1, attributeName, val)
j += 1
End While
i += 1
End While
' Now look in the /Comprobante/Impuestos element.
' NB we cannot use "//Impuestos" here
xpath = "/Comprobante/Impuestos"
' FOREACH /Comprobante/Impuestos//Retencion[j] element output the value of Importe
' Long xpath is /Comprobante/Impuestos/Retenciones/Retencion[j]
j = 1
While True
Dim xpath1 As String = xpath & "//Retencion[" & j & "]"
val = Sat.GetXmlAttribute(fname, attributeName, xpath1)
If Sat.XmlNoMatch() = val Then
Exit While
End If
Console.WriteLine("{0}/@{1}='{2}'", xpath1, attributeName, val)
j += 1
End While
' FOREACH /Comprobante/Impuestos//Traslado[j] element output the value of Importe
j = 1
While True
Dim xpath1 As String = xpath & "//Traslado[" & j & "]"
val = Sat.GetXmlAttribute(fname, attributeName, xpath1)
If Sat.XmlNoMatch() = val Then
Exit While
End If
Console.WriteLine("{0}/@{1}='{2}'", xpath1, attributeName, val)
j += 1
End While
End Sub
''' <summary>
''' Tests passing xmlDoc parameter as a Unicode UTF-16 string. Improved in [v9.2].
''' </summary>
Private Shared Sub test_XMLasUnicodeString()
Dim n As Integer
Dim s As String
Dim fname As String
Dim newname As String, password As String
Dim xmlStr As String
Dim elemName As String, attrName As String
Dim digest1 As String, digest2 As String
Console.WriteLine(vbLf & "READ IN A FILE TO A UNICODE UTF-16 STRING THEN PASS THE STRING AS XML DOC...")
fname = "cfdv33a-nomina12B.xml"
Console.WriteLine("FILE: {0}", fname)
' Read in file to a Unicode text string
xmlStr = File.ReadAllText(fname, Encoding.UTF8)
Console.WriteLine("xmlStr is {0} characters", xmlStr.Length)
Console.WriteLine(vbLf & "GET ATTRIBUTE VALUE USING UTF-16 STRING...")
' Attribute name contains non-ASCII character 'ü', Antigüedad="P3Y2M23D"
elemName = "nomina12:Receptor"
attrName = "Antigüedad"
s = Sat.GetXmlAttribute(xmlStr, attrName, elemName)
Console.WriteLine("{0}/@{1}='{2}'", elemName, attrName, s)
If s.Length = 0 Then
DisplayError()
End If
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
' Attribute name contains non-ASCII character 'ñ', Año="2016"
elemName = "nomina12:CompensacionSaldosAFavor"
attrName = "Año"
s = Sat.GetXmlAttribute(xmlStr, attrName, elemName)
Console.WriteLine("{0}/@{1}='{2}'", elemName, attrName, s)
If s.Length = 0 Then
DisplayError()
End If
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
' Attribute value contains non-ASCII character 'í', Sindicalizado="Sí"
elemName = "nomina12:Receptor"
attrName = "Sindicalizado"
s = Sat.GetXmlAttribute(xmlStr, attrName, elemName)
Console.WriteLine("{0}/@{1}='{2}'", elemName, attrName, s)
If s.Length = 0 Then
DisplayError()
End If
Debug.Assert(s.Length > 0, "Sat.GetXmlAttribute failed")
Console.WriteLine(vbLf & "CHECK XML IS OK USING UTF-16 STRING...")
n = Sat.ValidateXml(xmlStr)
Console.WriteLine("Sat.ValidateXml returns {0} (expecting 0)", n)
If n <> 0 Then
DisplayError(n)
End If
Debug.Assert(0 = n, "Sat.ValidateXml failed")
Console.WriteLine(vbLf & "MAKE PIPE STRING USING UTF-16 STRING...")
s = Sat.MakePipeStringFromXml(xmlStr)
Console.WriteLine("PIPESTRING=" & vbLf & "{0}", s)
If s.Length = 0 Then
DisplayError()
End If
Debug.Assert(s.Length > 0, "Sat.MakePipeStringFromXml failed")
Console.WriteLine(vbLf & "FORM MESSAGE DIGEST OF PIPE STRING USING UTF-16 STRING...")
s = Sat.MakeDigestFromXml(xmlStr)
Console.WriteLine("DIGEST={0}", s)
If s.Length = 0 Then
DisplayError()
End If
Debug.Assert(s.Length > 0, "Sat.MakeDigestFromXml failed")
Console.WriteLine(vbLf & "INSERT CERTIFICATE INTO XML USING UTF-16 STRING AS INPUT...")
newname = "cfdv33a-nomina12B-plus-cert.xml"
n = Sat.InsertCert(newname, xmlStr, "emisor.cer")
Console.WriteLine("Sat.InsertCert returns {0} (expecting 0)", n)
If n <> 0 Then
DisplayError(n)
End If
Debug.Assert(0 = n, "Sat.InsertCert failed")
Console.WriteLine("Created new file '{0}' length = {1}", newname, FileLength(newname))
' Query this new file for certificate details
s = Sat.QueryCert(newname, Query.organizationName)
Console.WriteLine("organizationName('{0}')='{1}'", newname, s)
Console.WriteLine(vbLf & "SIGN AN XML FILE WORKING ENTIRELY IN MEMORY...:")
Console.WriteLine("Read in private key and matching certificate to memory...")
password = "12345678a"
' CAUTION: DO NOT HARD-CODE REAL PASSWORDS!
' Read in the private key
Dim keyStr As String = Sat.GetKeyAsString("emisor.key", password, KeyOption.EncryptedPEM)
Console.WriteLine("Key string is {0} characters", keyStr.Length)
If keyStr.Length = 0 Then
DisplayError()
End If
' And the matching cert
Dim cerStr As String = Sat.GetCertAsString("emisor.cer")
Console.WriteLine("Cert string is {0} characters", cerStr.Length)
If cerStr.Length = 0 Then
DisplayError()
End If
Console.WriteLine("Check that the key and certificate are matched...")
n = Sat.CheckKeyAndCert(keyStr, password, cerStr)
Console.WriteLine("Sat.CheckKeyAndCert() returns {0} (expecting 0)", n)
If n <> 0 Then
DisplayError(n)
End If
Debug.Assert(0 = n, "Sat.CheckKeyAndCert failed")
' xmlStr already contains the unsigned XML doc, but we need XML data in bytes.
' As a test, we will force encoding of *input* string to be Latin-1
' but note the *output* will still be UTF-8.
Dim xmlArr As Byte() = System.Text.Encoding.GetEncoding("iso-8859-1").GetBytes(xmlStr)
Console.WriteLine("Unsigned xmlArr is {0} bytes", xmlArr.Length)
' Sign XML document with all parameters passed in memory
Dim xmlArrSigned As Byte() = Sat.SignXmlToBytes(xmlArr, keyStr, password, cerStr, 0)
Console.WriteLine("Sat.SignXmlToBytes(xmlArr) returns {0} bytes", xmlArrSigned.Length)
' Convert bytes back to Unicode string
' NB xmlStr now contains the *signed* document
xmlStr = System.Text.Encoding.UTF8.GetString(xmlArrSigned)
Console.WriteLine("xmlStr-signed is {0} characters", xmlStr.Length)
Console.WriteLine(vbLf & "CHECK SIGNED XML IS OK USING UTF-16 STRING...")
n = Sat.ValidateXml(xmlStr)
Console.WriteLine("Sat.ValidateXml(xmlStr-signed) returns {0} (expecting 0)", n)
If n <> 0 Then
DisplayError(n)
End If
Debug.Assert(0 = n, "Sat.ValidateXml failed")
Console.WriteLine(vbLf & "VALIDATE THE SIGNATURE USING UTF-16 STRING...")
n = Sat.VerifySignature(xmlStr)
Console.WriteLine("Sat.VerifySignature(xmlStr-signed) returns {0} (expecting 0)", n)
If n <> 0 Then
DisplayError(n)
End If
Debug.Assert(0 = n, "Sat.VerifySignature failed")
Console.WriteLine(vbLf & "GET CERTIFICATE ORGNAME USING UTF-16 STRING...")
' This time we have a result...
s = Sat.QueryCert(xmlStr, Query.organizationName)
Console.WriteLine("organizationName={0}", s)
If s.Length = 0 Then
DisplayError()
End If
Debug.Assert(s.Length > 0, "Sat.QueryCert failed")
Console.WriteLine(vbLf & "MAKE SIGNATURE USING UTF-16 STRING...")
s = Sat.MakeSignatureFromXml(xmlStr, keyStr, password)
Console.WriteLine("Sello={0}", s)
If s.Length = 0 Then
DisplayError()
End If
Debug.Assert(s.Length > 0, "Sat.MakeSignatureFromXml failed")
Console.WriteLine(vbLf & "EXTRACT SIGNATURE DIGEST USING UTF-16 STRING...")
s = Sat.ExtractDigestFromSignature(xmlStr)
Console.WriteLine("digest1={0}", s)
If s.Length = 0 Then
DisplayError()
End If
Debug.Assert(s.Length > 0, "Sat.ExtractDigestFromSignature failed")
digest1 = s
Console.WriteLine(vbLf & "MAKE MESSAGE DIGEST OF PIPE STRING USING UTF-16 STRING...")
s = Sat.MakeDigestFromXml(xmlStr)
Console.WriteLine("digest2={0}", s)
If s.Length = 0 Then
DisplayError()
End If
Debug.Assert(s.Length > 0, "Sat.MakeDigestFromXml failed")
digest2 = s
' The last two should match (ignore case)
n = String.Compare(digest1, digest2, True)
Console.WriteLine("String.Compare(digest1, digest2, ignoreCase) returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Digest values do not match")
End Sub
'*************************************
' LOCAL UTILITIES...
'*************************************
Private Shared Function FileIsNotPresent(filePath As String, message As String) As Boolean
Dim fi As New FileInfo(filePath)
If Not fi.Exists Then
Console.WriteLine(vbLf & "{0}: {1}", message, filePath)
Return True
End If
Return False
End Function
Private Shared Function FileLength(filePath As String) As Long
Dim fi As New FileInfo(filePath)
If Not fi.Exists Then
Return -1
End If
Return fi.Length
End Function
Private Shared Function FileHasBom(filePath As String) As Boolean
Const kNBYTES As Integer = 3
Dim buf As Byte() = New Byte(kNBYTES - 1) {}
Dim finfo As New FileInfo(filePath)
Debug.Assert(finfo.Exists, "File '" & filePath & "' does not exist.")
If finfo.Exists Then
Dim fsi As FileStream = finfo.OpenRead()
Dim br As New BinaryReader(fsi)
buf = br.ReadBytes(kNBYTES)
br.Close()
fsi.Close()
End If
' BOM consists of three bytes (0xEF, 0xBB, 0xBF)
Return (buf(0) = &Hef AndAlso buf(1) = &Hbb AndAlso buf(2) = &Hbf)
End Function
'* Display error - overloaded
Private Shared Sub DisplayError()
Console.WriteLine("ERROR: {0}", General.LastError())
End Sub
Private Shared Sub DisplayError(errCode As Integer)
Dim s As String = General.LastError()
Console.WriteLine("ERROR {0}: {1}: {2}", errCode, General.ErrorLookup(errCode), s)
End Sub
End Class
End Namespace