Extraer certificado digital en base64

1,574 views
Skip to first unread message

Luis Martinez Rguez.

unread,
Sep 7, 2019, 7:29:09 AM9/7/19
to Comunidad de Visual Foxpro en Español
Hola:
Necesito extraer un certificado digital en base64 de un fichero .pfx
Alguna idea ?

Saludos.
Luis Martinez
A Coruña
España




-----BEGIN CERTIFICATE----- -----END CERTIFICATE-----

Antonio Meza

unread,
Sep 7, 2019, 10:47:17 AM9/7/19
to Comunidad de Visual Foxpro en Español

Luis Martinez Rguez.

unread,
Sep 7, 2019, 3:20:45 PM9/7/19
to Comunidad de Visual Foxpro en Español
Me refiero a hacerlo desde VFP

Jean Pierre Adonis De La Cruz Garcia

unread,
Sep 7, 2019, 4:50:05 PM9/7/19
to Comunidad de Visual Foxpro en Español
Eso lo haces teniendo la clave del Certificado digital y despues de eso solo tendras q seguir los psos segun tu proveedor y solucionado

Fernando Mora

unread,
Sep 7, 2019, 8:40:45 PM9/7/19
to Comunidad de Visual Foxpro en Español
Hola Luis.
Usa CryptoAPI de Windows, aquí te armé un código de ejemplo realizando lo que solicitas. En este ejercicio se solicita la selección del archivo p12/pfx, y la contraseña. Esos datos se los pasamos a la función GetImportP12PFX, esta función valida que el archivo p12/pfx sea un blob pfx válido, luego verifica la contraseña, si todo esta correcto te devuelve un puntero a un almacén de certificados (certstore), esto debido a que un P12/PFX es un contenedor donde se pueden colocar varios certificados. 
El puntero a certstore que te devuelve la función antes mencionada, se lo pasamos a la función GetSelectCertificateFromCertStore, esta función te mostrará una ventana para que selecciones el certificado dentro de la lista de certificados que se encontraron en el PFX, podría ser solo uno, pero eso por ahora el sistema no lo puede saber. Seleccionas el certificado y la función te devolverá un puntero al contexto del certificado.
Ese puntero se lo pasamos a la función GetCertEncodex509 que te devuelve una cadena en formato ASN1 del certificado seleccionado, OJO, aquí no se exporta la clave privada, va solo el certificado para intercambio, esto es lo que se usa en facturación electrónica, intercambio de mensajes. etc.
Finalmente, la cadena ASN1 la pasamos a la función GetCryptBinaryToString junto con la constante CRYPT_STRING_BASE64HEADER, que nos devolverá el certificado en formato Base64 con encabezados de inicio y fin de certificado. Normalmente a este archivo se lo almacena con la extensión PEM que indica que es un certificado en formato Base64.

Saludos!
Fernando Mora
Machala - Ecuador


#DEFINE CRYPT_EXPORTABLE 0x00000001
#DEFINE FORMAT_MESSAGE_FROM_SYSTEM 0x00001000
#DEFINE CRYPT_STRING_BASE64HEADER 0x00000000

=SetDeclarationsAPI()
cFileP12PFX=GETFILE("P12,PFX")
IF EMPTY(cFileP12PFX)
RETURN
ENDIF 
cPassword=INPUTBOX("Ingrese password:")
lhStore = GetImportP12PFX(cFileP12PFX, cPassword)
IF lhStore=0
RETURN
ENDIF
pCertContext=GetSelectCertificateFromCertStore(lhStore)
IF pCertContext=0
RETURN
ENDIF
cX509ASN1 = GetCertEncodex509(pCertContext)
IF EMPTY(cX509ASN1)
RETURN
ENDIF
cX509Base64 = GetCryptBinaryToString(cX509ASN1, CRYPT_STRING_BASE64HEADER)
IF EMPTY(cX509Base64)
RETURN
ENDIF
cPath=ADDBS(JUSTPATH(cFileP12PFX)) + JUSTSTEM(cFileP12PFX) + ".PEM"
STRTOFILE(cX509Base64, cPath)
MESSAGEBOX("Certificado exportado a formato PEM con éxito", 64, _SCREEN.Caption)
CertFreeCertificateContext(pCertContext)
CertCloseStore(lhStore, 0)

PROCEDURE GetImportP12PFX()
LPARAMETERS tcArchivoPfx AS String, tcPassword AS String
hStoreHandle = 0
IF !EMPTY(tcArchivoPfx)
*----- Armamos la Estructura CRYPT_DATA_BLOB 
StrPfx = FILETOSTR(tcArchivoPfx)
cbData = LEN(StrPfx)
pbData = HeapAlloc(GetProcessHeap(), 0, cbData)
RtlMoveMemory(pbData, @StrPfx, cbData)
pPFX = 0h + BINTOC(cbData,"4RS") + BINTOC(pbData, "4RS")
*----- Verificamos que el archivo sea certificado Pfx, P12
IF PFXIsPFXBlob(pPFX)>0
*----- Capturamos el Password
cPassword = STRCONV(tcPassword,5) + CHR(0)
*----- Verificamos el Password
IF PFXVerifyPassword(pPFX, cPassword, 0)>0
*----- Importamos el o los certificados (pueden venir varios cert empaquetados en un P12 o PFX)
hStoreHandle = PFXImportCertStore(pPFX, cPassword, CRYPT_EXPORTABLE)
cPassword = ""
pPFX = ""
IF hStoreHandle=0
GetMessageError()
ENDIF
ELSE
GetMessageError()
ENDIF
ELSE
GetMessageError()
ENDIF
HeapFree(GetProcessHeap(), 0, pbData)
ELSE
GetMessageError()
ENDIF
RETURN hStoreHandle
ENDPROC

PROCEDURE GetSelectCertificateFromCertStore()
LPARAMETERS tnStoreHandle AS Long
lpCertContext = 0
lpCertContext=CryptUIDlgSelectCertificateFromStore(tnStoreHandle, 0, null, null, 1, 0, null)
RETURN lpCertContext
ENDPROC

PROCEDURE GetCertEncodex509()
LPARAMETERS tpCertContext AS Long
cAsn1CertEncode = ""
IF tpCertContext>0
cCERT_CONTEXT = SYS(2600, tpCertContext, 20)
nCertType = CTOBIN(SUBSTR(cCERT_CONTEXT, 1, 4), "4RS") && Tipo Certificado
cCertBuffer = CTOBIN(SUBSTR(cCERT_CONTEXT, 5, 4), "4RS") && Certificado Codificado
nCertLength = CTOBIN(SUBSTR(cCERT_CONTEXT, 9, 4), "4RS") && Longitud de Certificado
cCERT_INFO = CTOBIN(SUBSTR(cCERT_CONTEXT, 13, 4), "4RS") && Puntero a región CertInfo
nCertSotre = CTOBIN(SUBSTR(cCERT_CONTEXT, 17, 4), "4RS") && Manejador Certificado
cAsn1CertEncode = SYS(2600, cCertBuffer, nCertLength)
ENDIF
RETURN cAsn1CertEncode
ENDPROC

PROCEDURE GetCryptBinaryToString()
LPARAMETERS tcStringToConvert AS String, tnHexorBase64 AS Integer
lcRespStr = ""
IF VARTYPE(tcStringToConvert)=="C" OR VARTYPE(tnHexorBase64)=="N"
pbBinary = tcStringToConvert
cbBinary = LEN(pbBinary)
dwFlags = tnHexorBase64
pcchString = 0
pszString = ""
nResp = CryptBinaryToString(@pbBinary, cbBinary, dwFlags, NULL, @pcchString)
IF nResp>0
pszString = SPACE(pcchString)
nResp = CryptBinaryToString(@pbBinary, cbBinary, dwFlags, @pszString, @pcchString)
ENDIF
lcRespStr = pszString
ENDIF
RETURN lcRespStr
ENDPROC

PROCEDURE GetMessageError()
LPARAMETERS tnNumError
IF VARTYPE(tnNumError)=="N"
lnErrorCode = tnNumError
ELSE
lnErrorCode = GetLastError()
ENDIF
lcErrorMessage = SPACE(128)
=FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 'WINERROR.H', lnErrorCode, 0, @lcErrorMessage, 128 , 0)
MESSAGEBOX(lcErrorMessage , 16, _SCREEN.Caption)
ENDPROC

PROCEDURE SetDeclarationsAPI()
DECLARE LONG PFXIsPFXBlob IN Crypt32;
STRING pPFX

DECLARE LONG PFXVerifyPassword IN Crypt32;
STRING pPFX,;
STRING   szPassword,;
LONG dwFlags

DECLARE LONG PFXImportCertStore IN Crypt32;
STRING pPFX,;
STRING szPassword,;
LONG dwFlags
DECLARE LONG CertCreateCertificateContext IN Crypt32;
LONG dwCertEncodingType,;
STRING pbCertEncoded,;
LONG cbCertEncoded
DECLARE LONG CryptUIDlgSelectCertificateFromStore IN Cryptui;
LONG hCertStore,;
LONG hWnd, ;
STRING @pwszTitle, ;
STRING @pwszDisplayString, ;
LONG dwDontUseColumn, ;
LONG dwFlags,;
STRING pvReserved
DECLARE LONG CertFreeCertificateContext IN Crypt32;
LONG pCertContext

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

DECLARE LONG CryptBinaryToString IN Crypt32;
STRING pbBinary, ;
LONG cbBinary, ;
LONG dwFlags,;
STRING @pszString, ;
LONG @pcchString

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
ENDPROC




Luis Martinez Rguez.

unread,
Sep 8, 2019, 5:53:02 AM9/8/19
to Comunidad de Visual Foxpro en Español
Hola Fernando:
Muchas gracias por tu ayuda y por compartir tus conocimientos.

Rodribezul

unread,
Feb 9, 2020, 4:37:56 PM2/9/20
to Comunidad de Visual Foxpro en Español
Hola Fernando,

Siguiente tu orientación  de 

GetImportP12PFX
CertStore (hStore)
GetCryptUIDlgSelectCertificateFromStore
GetNotAfter que te devolverá la fecha-hora de caducidad del certificado.

No encuentro esas funciones , seria tan amable de indicarme donde las busco.

Gracias

Fernando Mora

unread,
Feb 10, 2020, 7:51:04 PM2/10/20
to Comunidad de Visual Foxpro en Español
Revisaste el codigo del primer post de este hilo, ahi estan las funciones. Con excepcion de GetNotAfter, que esta en otro hilo en este mismo foro.

Manuel Marin Montalvan

unread,
Feb 7, 2025, 11:39:10 AM2/7/25
to Comunidad de Visual Foxpro en Español
Excelente aporto estimado Fernando, estuve siguiendo tus publicaciones... y quisiera preguntarte, cómo se podría hacer la canonización de un archivo XMl con Foxpro..., he tratado de ubicar un procedimiento que pueda ayudarme sin necesidad de productos de terceros, pero no lo encontré, sé que hay procedimientos nativos de windows que se pueden usar para poder hacer la canonización del archivo XML, como por ejemplo WsStartReaderCanonicalization, WS_XML_CANONICALIZATION_ALGORITHM , etc. El problema que no hay bibliografía para su utilización en foxpro. por favor Fernando, podrías explicarnos cómo canonicar el archivo XML, para la firma digital de la factura electrónica con Visual foxpro o si hay algúna manera de canonizar un archivo XML con visual foxpro.

HernanCano

unread,
Apr 21, 2025, 9:26:06 PM4/21/25
to Comunidad de Visual Foxpro en Español
Canonicalization of an XML document

Signing an XML document using XMLDSIG (Part 2)

Sigue los pasos que se mencionan.
Agunos puedes obviarlos ---si los entiendes---; ottros no son necesarios.

En última instancia sólo son importantes:
- Remover comentarios: el XML que genero lo genero así, sin comentarios.
- "Line breaks normalized to #xA": o sea cam,biar todos los CHR(13)+CHR(10) por CHR(13): fácil desde VFP.
- Que todo el XML esté en una sola línea: el XML que genero lo genero así.
- Quitar en renglón de encabezado (el q empieza por <?xml...): fácil desde VFP.
- Agregar los NameSpaces: estoy analizando si ésto es lo q me impide avanzar (los agrego, pero la firma --al final-- me sale inválida, y no se sabe por qué).
- Convertir a UTF-8: fácil desde VFP.
....
....
etc
....
....
Escríbeme y avancemos juntos.
300-782.48.44.
CO.

Jairo Cedeño

unread,
Apr 21, 2025, 11:19:02 PM4/21/25
to Comunidad de Visual Foxpro en Español
Felicidades, Fernando puedo observar que manejas muy bien las apis de Windows para el terma de firmado!
Reply all
Reply to author
Forward
0 new messages