Fox obteniendo Cadena de Certificados, CertGetCertificateChain

751 views
Skip to first unread message

Fernando Mora

unread,
Sep 26, 2019, 12:32:10 AM9/26/19
to Comunidad de Visual Foxpro en Español
Para ciertos casos de facturación electrónica, solicitan incluir la cadena de confianza del certificado digital con el que se ha firmado el Xml, Con Fox podemos cumplir con ese requisito. El siguiente es un ejemplo del armado del nodo Signature con el subnodo KeyInfo incluyendo los tres certificados digitales de la cadena de confianza, Certificado de Entidad Final, Certificado CA y certificado ROOT.

Para que no se vea una fea cadena larga con los caracteres del certificado  digital en una sola línea, se creo una función GetString76 que devuelve la cadena con saltos cada 76 caracteres, el CHR(10) es un caracter totalmente válido para este proceso. 

Saludos Foxeros, y larga vida al zorro!
Fernando,

PD: Este ejemplo es válido para los certificados instalados en el almacén de certificados del sistema. Si desea probar des contenedor P12/PFX vea la función GetImportP12PFX para obtener un contexto a su certificado.


*--------------- Constantes
#DEFINE FORMAT_MESSAGE_FROM_SYSTEM 0x00001000
#DEFINE X509_ASN_ENCODING 1  
#DEFINE PKCS_7_ASN_ENCODING 0x00010000
*--------------- Constantes CertCreateCertificateChainEngine
#DEFINE CERT_CHAIN_CACHE_END_CERT 0x00000001
#DEFINE CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL 0x00000004
#DEFINE CERT_CHAIN_USE_LOCAL_MACHINE_STORE 0x00000008
#DEFINE CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE 0x00000010
#DEFINE CERT_CHAIN_ENABLE_SHARE_STORE 0x00000020
#DEFINE CERT_CHAIN_DISABLE_AIA 0x00002000
*------ Constantes CertOpenStore para: lpszStoreProvider 
#define CERT_STORE_PROV_MSG        1
#define CERT_STORE_PROV_MEMORY      2
#define CERT_STORE_PROV_FILE        3
#define CERT_STORE_PROV_REG        4
#define CERT_STORE_PROV_PKCS7      5
#define CERT_STORE_PROV_SERIALIZED 6
#define CERT_STORE_PROV_FILENAME_A 7
#define CERT_STORE_PROV_FILENAME_W 8
#define CERT_STORE_PROV_SYSTEM_A    9
#define CERT_STORE_PROV_SYSTEM_W    10
#DEFINE CERT_STORE_PROV_COLLECTION 11
#define CERT_STORE_PROV_SYSTEM_REGISTRY_A 12
#define CERT_STORE_PROV_SYSTEM_REGISTRY_W 13
#define CERT_STORE_PROV_SYSTEM_REGISTRY CERT_STORE_PROV_SYSTEM_REGISTRY_W
#define CERT_STORE_PROV_PHYSICAL_W 14
#define CERT_STORE_PROV_PHYSICAL CERT_STORE_PROV_PHYSICAL_W
#define CERT_STORE_PROV_SMART_CARD_W 15
#define CERT_STORE_PROV_SMART_CARD CERT_STORE_PROV_SMART_CARD_W
#define CERT_STORE_PROV_LDAP_W 16
#define CERT_STORE_PROV_LDAP CERT_STORE_PROV_LDAP_W
#define CERT_STORE_PROV_PKCS12 17
*------ Constantes CertOpenStore para:
#DEFINE PKCS_7_ASN_ENCODING 65536
#DEFINE X509_ASN_ENCODING 1
*------ Constantes CertOpenStore para: dwFlags
#DEFINE CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
#DEFINE CERT_SYSTEM_STORE_LOCATION_MASK          0x00FF0000
#DEFINE CERT_SYSTEM_STORE_LOCATION_SHIFT        16
#DEFINE CERT_SYSTEM_STORE_CURRENT_USER_ID        1
#DEFINE CERT_SYSTEM_STORE_LOCAL_MACHINE_ID      2
#DEFINE CERT_SYSTEM_STORE_CURRENT_SERVICE_ID    4
#DEFINE CERT_SYSTEM_STORE_SERVICES_ID            5
#DEFINE CERT_SYSTEM_STORE_USERS_ID              6
#DEFINE CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY_ID 7
#DEFINE CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY_ID 8
#DEFINE CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE_ID 9
#DEFINE CERT_SYSTEM_STORE_CURRENT_USER BITLSHIFT(1,16)
#DEFINE CERT_SYSTEM_STORE_LOCAL_MACHINE BITLSHIFT(2,16)
#DEFINE CERT_SYSTEM_STORE_CURRENT_SERVICE BITLSHIFT(4,16)
#DEFINE CERT_SYSTEM_STORE_SERVICES BITLSHIFT(5,16)
#DEFINE CERT_SYSTEM_STORE_USERS BITLSHIFT(6,16)
#DEFINE CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY BITLSHIFT(7,16)
#DEFINE CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY BITLSHIFT(8,16)
#DEFINE CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE BITLSHIFT(9,16)
*------ Constantes CryptUIDlgSelectCertificateFromStore para: dwDontUseColumn
#DEFINE CRYPTUI_SELECT_ISSUEDTO_COLUMN 0x000000001
#DEFINE CRYPTUI_SELECT_ISSUEDBY_COLUMN 0x000000002
#DEFINE CRYPTUI_SELECT_INTENDEDUSE_COLUMN 0x000000004
#DEFINE CRYPTUI_SELECT_FRIENDLYNAME_COLUMN 0x000000008
#DEFINE CRYPTUI_SELECT_LOCATION_COLUMN 0x000000010
#DEFINE CRYPTUI_SELECT_EXPIRATION_COLUMN 0x000000020
*------ Constantes Structure CERT_USAGE_MATCH para: dwType
#DEFINE USAGE_MATCH_TYPE_AND 0
#DEFINE USAGE_MATCH_TYPE_OR 1

=SetDeclatarionsAPIS()
hStore = GetCertOpenStore("MY")
IF hStore>0
lpCertContext = GetCryptUIDlgSelectCertificateFromStore(hStore)
IF lpCertContext=0
RETURN
ENDIF
ENDIF
lcNodeChain = GetXmlNodeCertificateChain(lpCertContext)
SET STEP ON
lcXml = ''
lcXml = lcXml + '<?xml version="1.0" encoding="UTF-8"?>' + CHR(10)
lcXml = lcXml + '<fe:Facturae xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:fe="http://www.facturae.es/Facturae/2009/v3.2/Facturae">' + CHR(10)
lcXml = lcXml + '<ds:Signature Id="Signature-09047b91-07dd-4e35-ac44-5e6c5fddcc0b-Signature" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">' + CHR(10)
lcXml = lcXml + '<ds:KeyInfo Id="Signature-09047b91-07dd-4e35-ac44-5e6c5fddcc0b-KeyInfo">' + CHR(10)
lcXml = lcXml + '<ds:X509Data>' + CHR(10)
lcXml = lcXml + lcNodeChain
lcXml = lcXml + '</ds:X509Data>' + CHR(10)
lcXml = lcXml + '</ds:KeyInfo>' + CHR(10)
lcXml = lcXml + '</ds:Signature>' + CHR(10)
lcXml = lcXml + '</fe:Facturae>'
STRTOFILE(lcXml, "C:\XMLCHAIN.XML")
nResp1 = CertFreeCertificateContext(lpCertContext)
nResp3 = CertCloseStore(hStore, 0)

PROCEDURE GetXmlNodeCertificateChain()
LPARAMETERS tpCertContext AS Long
nElement = GetCertGetCertificateChain(tpCertContext)
IF nElement>0
IF VARTYPE(_SCREEN.ArrayChain)#"U"
lcNode = ""
FOR X = 1 TO ALEN(_SCREEN.ArrayChain,1)
lcNode = lcNode + "<x509Certificate>"
lcNode = lcNode + GetString76(STRCONV(GetCertificateEncoded(_SCREEN.ArrayChain(X)),13))
lcNode = lcNode + "</x509Certificate>"
CertFreeCertificateContext(_SCREEN.ArrayChain(X))
NEXT
REMOVEPROPERTY(_SCREEN, "ArrayChain")
RETURN lcNode
ENDIF
ENDIF
ENDPROC

PROCEDURE GetCertificateEncoded()
LPARAMETERS tpCertContext AS Long
lbCertEncoded = ""
IF tpCertContext>0
lcCertContext = SYS(2600, tpCertContext, 20)
lpCertEncoded = CTOBIN(SUBSTR(lcCertContext, 5, 4), "4RS")
lnCertEncoded = CTOBIN(SUBSTR(lcCertContext, 9, 4), "4RS")
lbCertEncoded = SYS(2600, lpCertEncoded, lnCertEncoded)
ENDIF
RETURN lbCertEncoded
ENDPROC

PROCEDURE GetString76()
LPARAMETERS tcStringB64 AS String
LOCAL lcString76
lcString76 = ""
IF VARTYPE(tcStringB64)=="C"
FOR I = 1 TO LEN(tcStringB64) STEP 76
lcString76 = lcString76 + SUBSTR(tcStringB64, I, 76) + CHR(10)
NEXT
ENDIF
RETURN lcString76
ENDPROC

PROCEDURE GetCertGetCertificateChain()
LPARAMETERS tpCertContext AS Long
hChainEngine = 0
pCertContext = tpCertContext
pTime = 0
hAdditionalStore = 0
pChainPara = SetStructure_CERT_CHAIN_PARA()
dwFlags = 0
pvReserved = 0
ppChainContext = 0
nResp1 = CertGetCertificateChain(hChainEngine, pCertContext, pTime, hAdditionalStore, pChainPara, dwFlags, pvReserved, @ppChainContext)
nElement = GetStructure_CERT_CHAIN_CONTEXT(ppChainContext)
*nResp2 = CertFreeCertificateChain(ppChainContext)
RETURN nElement 
ENDPROC

PROCEDURE SetStructure_CERT_CHAIN_PARA()
*!* typedef struct _CERT_CHAIN_PARA {
*!*   DWORD                   cbSize;
*!*   CERT_USAGE_MATCH        RequestedUsage;
*!*   CERT_USAGE_MATCH        RequestedIssuancePolicy;
*!*   DWORD                   dwUrlRetrievalTimeout;
*!*   BOOL                    fCheckRevocationFreshnessTime;
*!*   DWORD                   dwRevocationFreshnessTime;
*!*   LPFILETIME              pftCacheResync;
*!*   PCCERT_STRONG_SIGN_PARA pStrongSignPara;
*!*   DWORD                   dwStrongSignFlags;
*!* } CERT_CHAIN_PARA, *PCERT_CHAIN_PARA
RequestedUsage = SetStructure_CERT_USAGE_MATCH()
RequestedIssuancePolicy = ""
dwUrlRetrievalTimeout = ""
fCheckRevocationFreshnessTime = ""
dwRevocationFreshnessTime = ""
pftCacheResync = ""
pStrongSignPara = ""
dwStrongSignFlags = ""
cbSize = BINTOC(4 + LEN(RequestedUsage), "4RS")
CERT_CHAIN_PARA = 0h + cbSize + RequestedUsage 
RETURN CERT_CHAIN_PARA
ENDPROC

PROCEDURE SetStructure_CERT_USAGE_MATCH()
*!* struct _CERT_USAGE_MATCH {
*!*   DWORD             dwType;
*!*   CERT_ENHKEY_USAGE Usage;
*!* } CERT_USAGE_MATCH, *PCERT_USAGE_MATCH
dwType = BINTOC(USAGE_MATCH_TYPE_AND, "4RS")
Usage = BINTOC(0, "4RS") + BINTOC(0, "4RS")
CERT_USAGE_MATCH = dwType + Usage 
RETURN CERT_USAGE_MATCH 
ENDPROC

PROCEDURE GetStructure_CERT_CHAIN_CONTEXT()
LPARAMETERS tppChainContext AS Long
*!* typedef struct _CERT_CHAIN_CONTEXT {
*!*   DWORD                cbSize;
*!*   CERT_TRUST_STATUS    TrustStatus;
*!*   DWORD                cChain;
*!*   PCERT_SIMPLE_CHAIN   *rgpChain;
*!*   DWORD                cLowerQualityChainContext;
*!*   PCCERT_CHAIN_CONTEXT *rgpLowerQualityChainContext;
*!*   BOOL                 fHasRevocationFreshnessTime;
*!*   DWORD                dwRevocationFreshnessTime;
*!*   DWORD                dwCreateFlags;
*!*   GUID                 ChainId;
*!* } CERT_CHAIN_CONTEXT, *PCERT_CHAIN_CONTEXT
cbSize = CTOBIN(SYS(2600, tppChainContext, 4), "4RS")
CHAIN_CONTEXT = SYS(2600, tppChainContext, cbSize)
TrustStatus_dwErrorStatus = CTOBIN(SUBSTR(CHAIN_CONTEXT, 5, 4), "4RS")
TrustStatus_dwInfoStatus = CTOBIN(SUBSTR(CHAIN_CONTEXT, 9, 4), "4RS")
cChain = CTOBIN(SUBSTR(CHAIN_CONTEXT,13, 4), "4RS")
rgpChain = CTOBIN(SUBSTR(CHAIN_CONTEXT,17, 4), "4RS")
cLowerQualityChainContext = CTOBIN(SUBSTR(CHAIN_CONTEXT,21, 4), "4RS")
rgpLowerQualityChainContext = CTOBIN(SUBSTR(CHAIN_CONTEXT,25, 4), "4RS")
fHasRevocationFreshnessTime = CTOBIN(SUBSTR(CHAIN_CONTEXT,29, 4), "4RS")
dwRevocationFreshnessTime = CTOBIN(SUBSTR(CHAIN_CONTEXT,33, 4), "4RS")
dwCreateFlags = CTOBIN(SUBSTR(CHAIN_CONTEXT,37, 4), "4RS")
ChainId = CTOBIN(SUBSTR(CHAIN_CONTEXT,41, 4), "4RS")
oPoint1 = CTOBIN(SUBSTR(CHAIN_CONTEXT,45, 4), "4RS")
oPoint2 = CTOBIN(SUBSTR(CHAIN_CONTEXT,49, 4), "4RS")
oPoint3 = CTOBIN(SUBSTR(CHAIN_CONTEXT,53, 4), "4RS")
nElement  = GetStructure_CERT_SIMPLE_CHAIN(rgpChain, cChain)
RETURN nElement
ENDPROC

PROCEDURE GetStructure_CERT_SIMPLE_CHAIN()
LPARAMETERS tprgpChain AS Long, tncChain AS Long
*!* typedef struct _CERT_SIMPLE_CHAIN {
*!*   DWORD                 cbSize;
*!*   CERT_TRUST_STATUS     TrustStatus;
*!*   DWORD                 cElement;
*!*   PCERT_CHAIN_ELEMENT   *rgpElement;
*!*   PCERT_TRUST_LIST_INFO pTrustListInfo;
*!*   BOOL                  fHasRevocationFreshnessTime;
*!*   DWORD                 dwRevocationFreshnessTime;
*!* } CERT_SIMPLE_CHAIN, *PCERT_SIMPLE_CHAIN
lpSimpleChain = CTOBIN(SYS(2600, tprgpChain, 4), "4RS")
cbSize = CTOBIN(SYS(2600, lpSimpleChain, 4), "4RS")
SIMPLE_CHAIN = SYS(2600, lpSimpleChain, cbSize)
TrustStatus_dwErrorStatus = CTOBIN(SUBSTR(SIMPLE_CHAIN, 5, 4), "4RS")
TrustStatus_dwInfoStatus = CTOBIN(SUBSTR(SIMPLE_CHAIN, 9, 4), "4RS")
cElement = CTOBIN(SUBSTR(SIMPLE_CHAIN,13, 4), "4RS")
rgpElement = CTOBIN(SUBSTR(SIMPLE_CHAIN,17, 4), "4RS")
pTrustListInfo = CTOBIN(SUBSTR(SIMPLE_CHAIN,21, 4), "4RS")
fHasRevocationFreshnessTime = CTOBIN(SUBSTR(SIMPLE_CHAIN,25, 4), "4RS")
dwRevocationFreshnessTime = CTOBIN(SUBSTR(SIMPLE_CHAIN,29, 4), "4RS")
GetStructure_CERT_CHAIN_ELEMENT(rgpElement, cElement)
RETURN cElement
ENDPROC

PROCEDURE GetStructure_CERT_CHAIN_ELEMENT()
LPARAMETERS trgpElement AS Long, tncElement AS Long
*!* typedef struct _CERT_CHAIN_ELEMENT {
*!*   DWORD                 cbSize;
*!*   PCCERT_CONTEXT        pCertContext;
*!*   CERT_TRUST_STATUS     TrustStatus;
*!*   PCERT_REVOCATION_INFO pRevocationInfo;
*!*   PCERT_ENHKEY_USAGE    pIssuanceUsage;
*!*   PCERT_ENHKEY_USAGE    pApplicationUsage;
*!*   LPCWSTR               pwszExtendedErrorInfo;
*!* } CERT_CHAIN_ELEMENT, *PCERT_CHAIN_ELEMENT
IF VARTYPE(_SCREEN.ArrayChain)<>"U"
REMOVEPROPERTY(_SCREEN, "ArrayChain")
ENDIF
_SCREEN.AddProperty("ArrayChain(1)")
CHAIN_ELEMENTS = SYS(2600, trgpElement, (tncElement*4))
nIniChr=1
FOR W = 1 TO tncElement
DIMENSION _SCREEN.ArrayChain(W)
lpChainElement = CTOBIN(SUBSTR(CHAIN_ELEMENTS, nIniChr, 4), "4RS")
cbSize = CTOBIN(SYS(2600, lpChainElement, 4), "4RS")
ChainElement = SYS(2600, lpChainElement, cbSize)
pCertContext = CTOBIN(SUBSTR(ChainElement,5,4), "4RS")
TrustStatus_dwErrorStatus = CTOBIN(SUBSTR(ChainElement, 9, 4), "4RS")
TrustStatus_dwInfoStatus = CTOBIN(SUBSTR(ChainElement, 13, 4), "4RS")
pRevocationInfo = CTOBIN(SUBSTR(ChainElement, 17, 4), "4RS")
pIssuanceUsage = CTOBIN(SUBSTR(ChainElement, 21, 4), "4RS")
pApplicationUsage = CTOBIN(SUBSTR(ChainElement, 25, 4), "4RS")
pwszExtendedErrorInfo = CTOBIN(SUBSTR(ChainElement, 29, 4), "4RS")
_SCREEN.ArrayChain(W) = pCertContext
nIniChr = nIniChr + 4
NEXT
ENDPROC

PROCEDURE GetCertOpenStore()
LPARAMETERS tcStoreName AS String
hStoreHandle = 0
lpszStoreProvider = CERT_STORE_PROV_SYSTEM_A
dwEncodingType = BITOR(PKCS_7_ASN_ENCODING, X509_ASN_ENCODING)
hCryptProv = 0
dwFlags = CERT_SYSTEM_STORE_CURRENT_USER
pvPara = "MY" + CHR(0)
hStoreHandle = CertOpenStore(lpszStoreProvider, dwEncodingType, hCryptProv, dwFlags, pvPara)
RETURN hStoreHandle
ENDPROC

PROCEDURE GetCryptUIDlgSelectCertificateFromStore()
LPARAMETERS thStore AS Long
pCertContext = 0
hCertStore = thStore
hWnd = _SCREEN.HWnd
pwszTitle = NULL
pwszDisplayString = NULL
dwDontUseColumn = 0
dwFlags = 0
pvReserved = NULL
pCertContext=CryptUIDlgSelectCertificateFromStore(hCertStore, hWnd, pwszTitle, pwszDisplayString, dwDontUseColumn, dwFlags, pvReserved)
RETURN pCertContext
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

PROCEDURE SetDeclatarionsAPIS()
DECLARE LONG CertOpenStore IN Crypt32;
LONG lpszStoreProvider,;
LONG dwEncodingType,;
LONG hCryptProv,;
LONG dwFlags,;
STRING pvPara

DECLARE LONG CertCloseStore IN Crypt32;
LONG hCertStore,;
LONG dwFlags

DECLARE LONG CertGetCertificateChain IN Crypt32;
LONG hChainEngine,;
LONG pCertContext,;
LONG pTime,;
LONG hAdditionalStore,;
STRING pChainPara,;
LONG dwFlags,;
LONG pvReserved,;
LONG @ppChainContext

DECLARE LONG CertFreeCertificateContext IN Crypt32;
LONG pCertContext

DECLARE LONG CertFreeCertificateChain IN Crypt32;
LONG pChainContext

*--------------- Cryptui
DECLARE LONG CryptUIDlgViewContext IN Cryptui;
LONG dwContextType,;
LONG pvContext,;
LONG hwnd,;
STRING pwszTitle,;
LONG dwFlags,;
LONG pvReserved

DECLARE LONG CryptUIDlgSelectCertificateFromStore IN Cryptui;
LONG hCertStore,;
LONG hWnd, ;
STRING @pwszTitle, ;
STRING @pwszDisplayString, ;
LONG dwDontUseColumn, ;
LONG dwFlags,;
STRING pvReserved

*--------------- Kernel32
DECLARE LONG GetLastError IN Kernel32

DECLARE LONG FormatMessage IN Kernel32;
  LONG dwFlags,;
  STRING @lpSource,;
  LONG dwMessageId,;
  LONG dwLanguageId,;
  STRING @lpBuffer,;
  LONG nSize,;
  LONG Arguments

ENDPROC




Jose Antonio Blasco

unread,
Sep 26, 2019, 11:50:05 AM9/26/19
to Comunidad de Visual Foxpro en Español
Buenas tardes Fernando,
He estado probando este nuevo código.    
Creo que junto con el código que publicaste en abril, y al que tu me hiciste referencia en el otro hilo, se puede llegar a lograr, pues también hace falta el "SignedInfo", SignatureValue, Object y Modulus.
Voy a ver si puedo juntar ambos códigos y armar la secuencia necesaria, pidiendo incluso el archivo XML a firmar.

Ya te diré.

Jose A. Blasco
Zaragoza - España
Visual FoxPro 9 SP2



--
Has recibido este mensaje porque estás suscrito al grupo "Comunidad de Visual Foxpro en Español" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a publicesvfoxp...@googlegroups.com.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/publicesvfoxpro/1717c914-f1cd-412a-84fd-6a6adbad0ac1%40googlegroups.com.

Roman Koltsov

unread,
Sep 26, 2019, 11:41:50 PM9/26/19
to Comunidad de Visual Foxpro en Español
Durante mucho tiempo soñé con tratar con la función CertGetCertificateChain en la VFP. Ahora lo has hecho. Bravo, Fernando!

William López

unread,
Sep 27, 2019, 10:04:02 AM9/27/19
to Comunidad de Visual Foxpro en Español
Excelente trabajo Fernando.  Muchas Gracias.



Alfredo Gómez Silva

unread,
Feb 6, 2020, 2:56:40 PM2/6/20
to Comunidad de Visual Foxpro en Español
Fernando tu trabajo facilita a muchos de nosotros, se te agradece y felicita por eso. Sólo me faltaba sellar los XML sin DLL, tus aportes los utilizo. Sabrás de algún link que todo se pueda hacer en en JAVA. Gracias de antemano

Fernando Mora

unread,
Feb 8, 2020, 9:05:46 PM2/8/20
to Comunidad de Visual Foxpro en Español
Saludos Alfredo.

No entendí tu pregunta. ¿quieres un link de Java? 

Rodribezul

unread,
Feb 9, 2020, 4:04:50 PM2/9/20
to Comunidad de Visual Foxpro en Español
Hola Fernando , esta función que nombras GetImportP12PFX , donde le ve uno.

Gracias


El miércoles, 25 de septiembre de 2019, 23:32:10 (UTC-5), Fernando Mora escribió:

Fernando Mora

unread,
Feb 10, 2020, 7:43:35 PM2/10/20
to Comunidad de Visual Foxpro en Español
Reply all
Reply to author
Forward
0 new messages