Para obtener el ticket se envia un mensaje generado con la firma electrónica utilizando SHA1+RSA.
Espacificacion Tecnica (Resumen de lo importante): https://www.afip.gob.ar/ws/WSAA/Especif ... _1.2.2.pdf
1.Generar el mensaje del TRA (LoginTicketRequest.xml)
2.Generar un CMS que contenga el TRA, su firma electrónica y el certificado X.509 (LoginTicketRequest.xml.cms)
3.Codificar en Base64 el CMS (LoginTicketRequest.xml.cms.bse64)
4.Invocar WSAA con el CMS y recibir LoginTicketResponse.xml
5.Extraer y validar la información de autorización (TA).
Aqui dejo el link del Web Service: https://www.afip.gob.ar/ws/documentacion/wsaa.asp
link del Manual del Desarrollador: https://www.afip.gob.ar/ws/WSAA/WSAAmanualDev.pdf
Buscando encontre que se pudo implementar con Visual Fox, hay varios links sobre eso pero me interesa el de este usuario que pudo manipular el certificado PFX, que es con el que nosotros trabajamos. El hilo es muy largo.
https://groups.google.com/g/publicesvfo ... CfnAsMAgAJ
Sobre el codigo en cuestion lo dejo aqui, la idea es poder traducirlo a Xailer y empezar a probar. De entrada la declaracion no la entiendo bien y despues hay 3 funciones que no las pude encontrar STRCONV, BINTOC, BINTOC creo que solo existen VFP, quizas alguna sea equivalente con Clipper.
Código: Seleccionar todo
*--------------- CryptoApi CSP
DECLARE LONG CertOpenSystemStore IN crypt32;
LONG hprov,;
STRING szSubsystemProtocol
DECLARE LONG CryptUIDlgSelectCertificateFromStore IN Cryptui;
LONG hCertStore,;
LONG hWnd,;
STRING @pwszTitle,;
STRING @pwszDisplayString,;
LONG dwDontUseColumn,;
LONG dwFlags,;
STRING pvReserved
DECLARE LONG CryptSignMessage IN Crypt32;
STRING pSignPara,;
LONG fDetachedSignature,;
INTEGER cToBeSigned,;
STRING @rgpbToBeSigned,;
STRING @rgcbToBeSigned,;
STRING @pbSignedBlob,;
LONG @pcbSignedBlob
DECLARE LONG CertFreeCertificateContext IN Crypt32;
LONG pCertContext
DECLARE LONG CertCloseStore IN Crypt32;
LONG hCertStore,;
LONG dwFlag
*--------------- Kernel
DECLARE LONG GetLastError IN Kernel32
DECLARE LONG FormatMessage IN Kernel32;
LONG dwFlags,;
STRING @lpSource,;
LONG dwMessageId,;
LONG dwLanguageId,;
STRING @lpBuffer,;
LONG nSize,;
LONG Arguments
DECLARE LONG GetProcessHeap IN Kernel32
DECLARE LONG HeapAlloc IN Kernel32;
LONG hHeap,;
LONG dwFlags,;
LONG dwBytes
DECLARE LONG HeapFree IN Kernel32;
LONG hHeap,;
LONG dwFlags,;
LONG lpMem
DECLARE RtlMoveMemory IN Kernel32;
LONG Destination,;
STRING @Source,;
LONG Length
*------------ Constantes
#DEFINE PKCS_7_ASN_ENCODING 0x00010000
#DEFINE X509_ASN_ENCODING 0x00000001
#DEFINE FORMAT_MESSAGE_FROM_SYSTEM 0x00001000
*AGREGADO POR MI
DECLARE LONG PFXImportCertStore IN Crypt32;
STRING @pfx,;
STRING szPassword,;
LONG dwFlags
DECLARE INTEGER PFXVerifyPassword IN Crypt32;
STRING pfx,;
STRING szPassword,;
LONG dwFlags
DECLARE INTEGER CertFindCertificateInStore IN crypt32;
INTEGER hCertStore,;
LONG dwCertEncodingType,;
LONG dwFindFlags,;
LONG dwFindType,;
INTEGER pvFindPara,;
INTEGER pPrevCertContext
#DEFINE szOID_NIST_sha512 "2.16.840.1.101.3.4.2.3"
*------------ Main
clear
cFileXML="archivo.xml"
IF EMPTY(cFileXML)
RETURN .F.
ENDIF
*!* **selecciona Certificado a traves de la interfase de usuario
*!* hStore = CertOpenSystemStore(0, "MY")
*!* pCertContext=CryptUIDlgSelectCertificateFromStore(hStore , 0, NULL, NULL, 1, 0, NULL)
*Seleccion Certificado directamente desde un archivo
*inicio
CerPFX = FILETOSTR("C:\PROYECTOS\NEWFPRG\SOURCE\WEBSERVICE\CERT\CERT.PFX")
clave = "123456"
clave = STRCONV(clave,5)+CHR(0)
cbData = LEN(CerPFX)
pbData = HeapAlloc(GetProcessHeap(), 0, cbData)
RtlMoveMemory(pbData, @CerPFX, cbData)
pPFX = 0h + BINTOC(cbData,"4RS")+ BINTOC(pbData,"4RS")
if PFXVerifyPassword(@pPFX,clave,0)=0
MESSAGEBOX( "La clave no es correcta" )
HeapFree(GetProcessHeap(), 0, pbData)
RETURN
ENDIF
hStore = PFXImportCertStore(@pPFX, clave, 0)
pCertContext = CertFindCertificateInStore(hStore,BITOR(PKCS_7_ASN_ENCODING, X509_ASN_ENCODING),0, 0, 0, 0)
*fin
IF pCertContext=0
=CertCloseStore(hStore, 0)
RETURN .F.
ENDIF
lcSignature=GetSignXml(cFileXML, pCertContext)
IF !EMPTY(lcSignature)
STRTOFILE(lcSignature,"C:\proyectos\newfprg\source\webservice\tickets\TRA_wsfe.TMP")
? lcSignature
lbReturn=.T.
ELSE
lbReturn=.F.
ENDIF
=CertCloseStore(hStore, 0)
=CertFreeCertificateContext(pCertContext)
RETURN lbReturn
*--------------- Región de Procedures
PROCEDURE GetSignXml(tcPathFileXml, tpCertContext)
*SET STEP ON
*----- Creamos Puntero de Memoria, colocamos el algoritmo de firma y armamos estructura CRYPT_ALGORITHM_IDENTIFIER
lcOID = szOID_NIST_sha512
lpOID = HeapAlloc(GetProcessHeap(), 0, LEN(lcOID))
RtlMoveMemory(lpOID, @lcOID, LEN(lcOID))
CRYPT_ALGORITHM_IDENTIFIER = 0h + BINTOC(lpOID,"4RS") + BINTOC(0, "4RS")
*----- Creamos Puntero de Memoria y colocamos el Certificado
lpCertificate = 0h + BINTOC(tpCertContext,"4RS")
lpRgpMsgCert = HeapAlloc(GetProcessHeap(), 0, LEN(lpCertificate))
RtlMoveMemory(lpRgpMsgCert, @lpCertificate, LEN(lpCertificate))
*----- Armamos la Estructura CRYPT_SIGN_MESSAGE_PARA
lnLenSP = 68 && (17 estructuras * 4 )
nMsgCert = 1
cbSize = BINTOC(lnLenSP,"4RS")
dwMsgEncodingType = BINTOC(BITOR(PKCS_7_ASN_ENCODING, X509_ASN_ENCODING),"4RS")
pSigningCert = BINTOC(tpCertContext,"4RS")
HashAlgorithm = CRYPT_ALGORITHM_IDENTIFIER + BINTOC(0, "4RS") + BINTOC(0, "4RS")
pvHashAuxInfo = 0h
cMsgCert = BINTOC(nMsgCert,"4RS")
rgpMsgCert = BINTOC(lpRgpMsgCert,"4RS")
*----- Resto de estructuras opcionales, rellenar con CHR(0)
*cMsgCrl, rgpMsgCrl, cAuthAttr, rgAuthAttr, cUnauthAttr, rgUnauthAttr,
*dwFlags, dwInnerContentType, HashEncryptionAlgorithm, pvHashEncryptionAuxInfo
pSignPara = 0h + cbSize + dwMsgEncodingType + pSigningCert + HashAlgorithm + pvHashAuxInfo + cMsgCert + rgpMsgCert
nlenpSign = LEN(pSignPara) + 1
pSignPara = pSignPara + REPLICATE(CHR(0), lnLenSP-nlenpSign)
*----- Cargamos el archivo Xml a Firmar
lcFileXmlIn = tcPathFileXml
lcXmlString = FILETOSTR(lcFileXmlIn)
*----- Colocamos la cadena Xml dentro de un puntero
lpByToSigned = HeapAlloc(GetProcessHeap(), 0, LEN(lcXmlString) + 1)
RtlMoveMemory(lpByToSigned, @lcXmlString, LEN(lcXmlString) + 1)
*----- Procedemos a Firmar el Xml
rgpbToBeSigned = 0h + BINTOC(lpByToSigned, "4RS")
lnXmlStrLen = LEN(lcXmlString)
rgcbToBeSigned = 0h + BINTOC(lnXmlStrLen, "4RS")
pcbSignedBlob = 0
pbSignedBlob = ""
IF CryptSignMessage(@pSignPara, 0, 1, @rgpbToBeSigned, @rgcbToBeSigned, @pbSignedBlob , @pcbSignedBlob)=0
pbSignedBlob = SPACE(pcbSignedBlob)
IF CryptSignMessage(@pSignPara, 0, 1, @rgpbToBeSigned, @rgcbToBeSigned, @pbSignedBlob, @pcbSignedBlob)=0
=GetMensajeError()
ENDIF
ENDIF
*----- Liberamos los punteros de memoria
HeapFree(GetProcessHeap(), 0, lpByToSigned)
HeapFree(GetProcessHeap(), 0, lpRgpMsgCert)
HeapFree(GetProcessHeap(), 0, lpOID)
RETURN pbSignedBlob
ENDPROC
PROCEDURE GetMensajeError(tcNumError)
IF VARTYPE(tcNumError)=="N"
lnErrorCode = tcNumError
ELSE
lnErrorCode = GetLastError()
ENDIF
lpBuffer = SPACE(128)
=FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 'WINERROR.H', lnErrorCode, 0, @lpBuffer, 128 , 0)
=MESSAGEBOX(lpBuffer, 16, "Error: " + TRANSFORM(lnErrorCode,"@0"))
ENDPROC