The CryptoSys PKI Toolkit now includes full support for the private key files
published by the
Servicio de Administración Tributaria
in Mexico.
The private key file
AAA010101AAA_0408021316S.key
provided as a test is a PKCS-8 file encrypted using PBES2/rc2CBC.
This key file can be read and decrypted using the CryptoSys PKI Toolkit.
A copy is included in the VB project below.
The original key file and lots of other information including a sample XML file
Muestra.xml (zipped, 1 kB) can be downloaded
from ftp://ftp2.sat.gob.mx in folder
/asistencia_ftp/publicaciones/solcedi
SAT Mexico Support | Signing and UTF-8 Data | Signing for SAT using C# | SAT X.509 Certificates and Base64 Format | SAT X.509 Certificate Serial Numbers
The catch with signing digital documents according to the SAT requirements is that the text must be in UTF-8 format before creating the MD5 message digest. This only matters where the text contains accented characters like áéíóúñ. If your original string is in Latin-1 format (8-bit ASCII) and includes an accented character, it will not create the correct message digest. We have a solution.
VB6 project to sign XML file to SAT requirements: MexicoSAT.zip (13 kB)
Quick-and-dirty VB code to detect UTF-8 strings: basUTF8.bas.
An in-built function to do the same thing: CNV_CheckUTF8
Jorge Perez has kindly prepared a port of MexicoSAT to PowerBuilder: see Example in Powerbuilder Script.
Download the C# project MexicoSATcsharp which demonstrates techniques
in signing and verifying data for SAT purposes, as well as how to verify an X.509 certificate.
You will need to re-reference the diCrSysPKINet.dll class library in your project.
The new functions
X509_ReadStringFromFile
and
X509_SaveFileFromString
introduced in version 3.0 of CryptoSys PKI now allow simple conversion of an X.509 certificate file to a base64 string and vice versa.
The certificate is stored in a one-line base64 string, which can be cut-and-pasted into an XML file, for example
<?xml version="1.0" encoding="UTF-8"?>
<Comprobante fecha="2005-09-02T16:30:00" folio="1" noAprobacion="1"
noCertificado="00001000000000000114"
certificado="MIIDWjCCAkKgAwIBAgIUMDAwMDExMDAwMDAyMDA..."
serie="A" version="1.0">
The following example from the manual reads in the base64 string from the SAT Mexico test certificate and displays it.
It then saves the string as a new certificate and uses the
X509_CertThumb
function to check that the two files are identical.
Dim nRet As Long Dim strCertString As String Dim strCertFile As String Dim strNewFile As String Dim strThumb1 As String Dim strThumb2 As String strCertFile = "aaa010101aaa_CSD.cer" ' Read in certificate file's data to a string nRet = X509_ReadStringFromFile("", 0, strCertFile, 0) Debug.Print "X509_ReadStringFromFile returns " & nRet If nRet <= 0 Then Exit Sub ' ERROR strCertString = String(nRet, " ") nRet = X509_ReadStringFromFile(strCertString, Len(strCertString), strCertFile, 0) Debug.Print "For certificate '" & strCertFile & "':" Debug.Print strCertString ' Save the string to a new certificate file, this time in PEM format strNewFile = "aaa010101aaa_CSD.pem.cer" nRet = X509_SaveFileFromString(strNewFile, strCertString, PKI_X509_FORMAT_PEM) Debug.Print "X509_SaveFileFromString returns " & nRet If nRet = 0 Then Debug.Print "Created new certificate file '" & strNewFile & "'" End If ' Check that the two certificate files are identical by computing their SHA-1 thumbprints strThumb1 = String(PKI_SHA1_CHARS, " ") strThumb2 = String(PKI_SHA1_CHARS, " ") nRet = X509_CertThumb(strCertFile, strThumb1, Len(strThumb1), 0) nRet = X509_CertThumb(strNewFile, strThumb2, Len(strThumb2), 0) Debug.Print "SHA-1(old)=" & strThumb1 Debug.Print "SHA-1(new)=" & strThumb2 If strThumb1 = strThumb2 Then Debug.Print "Certificates are identical" Else Debug.Print "ERROR: certificates do not match" End If
The output should look like this:
X509_ReadStringFromFile returns 1152 For certificate 'aaa010101aaa_CSD.cer': MIIDWjCCAkKgAwIBAgIUMDAwMDEx...7D5F8SB7Li3zt9vbbMzBc5xGg== X509_SaveFileFromString returns 0 Created new certificate file 'aaa010101aaa_CSD.pem.cer' SHA-1(old)=5791650d63340129568c1eecc6566b2fdd8bbd4c SHA-1(new)=5791650d63340129568c1eecc6566b2fdd8bbd4c Certificates are identical
Old code, now superseded: How to read an X.509 certificate file and convert to base64 format and vice versa: x509_base64.bas.
The X.509 standard is that the serial number is stored as an integer value. SAT in Mexico allocates serial numbers in the form of a hexadecimal-encoded value of a string of 20 ASCII digits, which represents an extremely large integer. Here is some VB6 code to extract the serial number in the required SAT format:
Dim nLen As Long Dim strCertFile As String Dim strSerialNumber As String Dim strSerialSAT As String ' Extract the certificate's serial number strCertFile = "AAA010101AAAsd.cer" nLen = X509_CertSerialNumber(strCertFile, "", 0, 0) If (nLen <= 0) Then Exit Sub strSerialNumber = String(nLen, " ") nLen = X509_CertSerialNumber(strCertFile, strSerialNumber, Len(strSerialNumber), 0) Debug.Print "X.509 Serial Number=0x" & strSerialNumber ' Decode from hex-encoded integer to string of ASCII digits strSerialSAT = StrConv(cnvBytesFromHexStr(strSerialNumber), vbUnicode) Debug.Print "Decoded SAT Format ='" & strSerialSAT & "'"
For the sample X.509 certificate provided by SAT (AAA010101AAAsd.cer), this should produce the following output:
X.509 Serial Number=0x3030303031303030303030303030303030313134 Decoded SAT Format ='00001000000000000114'
Note that the code above is only applicable for certificates with serial numbers in this particular format.
If you examine the test certificate
using Microsoft's CERTMGR.EXE program (just double-click on the .CER file in Windows Explorer),
you will see that the Serial Number value is given as
3030 3030 3130 3030 3030 3030 3030 3030 3031 3134
which is what our CryptoSys PKI program returns. This is the hexadecimal-encoded value of the decimal integer 275106190557734483187066766737145316642573594932 (2.75 x 1047), a number almost big enough to count every atom in the planet!
For more information, please Email Us.
This page last updated: 29 May 2009