* Constants for use with CryptoAPI function CryptGetObjectUrl
* to programmatically extract CRL list distribution point from a digital certificate (CDP)
* AIA extension - Authority Information Access contains AIA records and possibly even the OCSP URL (OID '1.3.6.1.5.5.7.1.1')
#DEFINE URL_OID_CERTIFICATE_ISSUER 1 && AIA: $urlType = URL_OID_CERTIFICATE_ISSUER
* CDP extension - CRL Distribution Points (OID '2.5.29.31')
#DEFINE URL_OID_CERTIFICATE_CRL_DIST_POINT 2 && CRL: $urlType = URL_OID_CERTIFICATE_CRL_DIST_POINT
#DEFINE URL_OID_CTL_ISSUER 3
#DEFINE URL_OID_CTL_NEXT_UPDATE 4
#DEFINE URL_OID_CRL_ISSUER 5
#DEFINE URL_OID_CERTIFICATE_FRESHEST_CRL 6
#DEFINE URL_OID_CRL_FRESHEST_CRL 7
#DEFINE URL_OID_CROSS_CERT_DIST_POINT 8
#DEFINE URL_OID_CERTIFICATE_OCSP 9
#DEFINE URL_OID_CERTIFICATE_OCSP_AND_CRL_DIST_POINT 10
#DEFINE URL_OID_CERTIFICATE_CRL_DIST_POINT_AND_OCSP 11
#DEFINE URL_OID_CROSS_CERT_SUBJECT_INFO_ACCESS 12
#DEFINE URL_OID_CERTIFICATE_ONLY_OCSP 13 && OCSP: $urlType = URL_OID_CERTIFICATE_ONLY_OCSP
#DEFINE CRYPT_GET_URL_FROM_PROPERTY 1
#DEFINE CRYPT_GET_URL_FROM_EXTENSION 2 && 0x2
#DEFINE CRYPT_GET_URL_FROM_UNAUTH_ATTRIBUTE 3
#DEFINE CRYPT_GET_URL_FROM_AUTH_ATTRIBUTE 8
Declare Function CryptGetObjectUrl Lib "cryptnet.dll" ( _
ByVal pszUrlOid As String, _
pvPara As Any, _
ByVal dwFlags As Long, _
ByRef pUrlArray As PCRYPT_URL_ARRAY, _
ByRef pcbUrlArray As Long, _
ByRef pUrlInfo As PCRYPT_URL_INFO, _
ByRef pcbUrlInfo As Long, _
pvReserved As Any) As Long
$signature = @"
[DllImport("cryptnet.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptGetObjectUrl(
int pszUrlOid,
IntPtr pvPara,
int dwFlags,
byte[] pUrlArray,
ref int pcbUrlArray,
IntPtr pUrlInfo,
ref int pcbUrlInfo,
int pvReserved
);
"@
DECLARE INTEGER CryptGetObjectUrl IN cryptnet;
STRING @ pszUrlOid,; && _In_ STRING OR INTEGER???
INTEGER pvPara,; && _In_
INTEGER dwFlags,; && _In_
LONG @ pUrlArray,; && _Out_ PCRYPT_URL_ARRAY && OR STRING @ pUrlArray? pUrlArray will contains a byte array that represents little-endian Unicode strings
LONG @ pcbUrlArray,; && _Inout_ DWORD *, pcbUrlArray will contain a number of bytes to use for pUrlArray byte array
LONG @ pUrlInfo,; && _Out_ PCRYPT_URL_INFO, not required for our task
LONG @ pcbUrlInfo,; && _Inout_ DWORD *, not required for our task
INTEGER pvReserved && _reserved_ LPVOID, not required for our task
pcbUrlArray = 0
pszUrlOid = BINTOC(2, "4RS") + Ñhr(0)
ret = CryptGetObjectUrl(@pszUrlOid, pCertContext, 0, NULL, @pcbUrlArray, NULL, NULL, NULL)
If ret = 0
lnResultCode = GetLastError()
lcErr = "Error by calling CryptGetObjectUrl"
=MessageBox(lcErr,16,"Error: " + Transform(lnResultCode,"@0"))
Else
pUrlArray = LocalAlloc(0x0040, m.pcbUrlArray) && Pointer to structure CRYPT_URL_ARRAY
* https://www.winehq.org/pipermail/wine-cvs/2009-December/062848.html
If !CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, pCertContext, 0, pUrlArray, @pcbUrlArray, NULL, NULL, NULL)=0
nBufSize=0
= CryptBinaryToString(@m.pUrlArray, Len(m.pUrlArray), CRYPT_STRING_BINARY, NULL, @nBufSize) && CRYPT_STRING_BINARY = 0x00000002
lcCDP_URL = REPLICATE(CHR(0), m.nBufSize)
If !CryptBinaryToString(@m.pUrlArray, Len(m.pUrlArray), CRYPT_STRING_BINARY, @lcCDP_URL, @nBufSize) = 0
If !Empty(hFile)
lcStr = "CRL List URL: " + AllT(lcCDP_URL)
FPuts(hFile, lcStr)
EndIf
Else
=MessageBox("Can't to retrieve CRL List URL from Certificate!",16,"Error")
EndIf
Else
=MessageBox("Cant't to obtain CRL point address!",16,"Error")
EndIf
LocalFree(pUrlInfo)
LocalFree(pUrlArray)
EndIf
* https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptbinarytostringa
* Constants for third parameter of CryptBinaryToStringA function
#DEFINE CRYPT_STRING_BASE64HEADER 0x00000000 && Base64, with certificate beginning and ending headers
#DEFINE CRYPT_STRING_BASE64 0x00000001 && Base64, without headers
#DEFINE CRYPT_STRING_BINARY 0x00000002 && Pure binary copy
#DEFINE CRYPT_STRING_BASE64REQUESTHEADER 0x00000003 && Base64, with request beginning and ending headers
#DEFINE CRYPT_STRING_HEX 0x00000004 && Hexadecimal only
#DEFINE CRYPT_STRING_HEXASCII 0x00000005 && Hexadecimal, with ASCII character display
#DEFINE CRYPT_STRING_BASE64X509CRLHEADER 0x00000009 && Base64, with X.509 CRL beginning and ending headers
#DEFINE CRYPT_STRING_HEXADDR 0x0000000A && Hexadecimal, with address display
#DEFINE CRYPT_STRING_HEXASCIIADDR 0x0000000B && Hexadecimal, with ASCII character and address display
#DEFINE CRYPT_STRING_HEXRAW 0x0000000C && A raw hexadecimal string. Windows Server 2003 and Windows XP: This value is not supported
#DEFINE CRYPT_STRING_STRICT 0x20000000 && Enforce strict decoding of ASN.1 text formats. Some ASN.1 binary BLOBS can have the first few bytes of the BLOB incorrectly interpreted as Base64 text. In this case, the rest of the text is ignored. Use this flag to enforce complete decoding of the BLOB. Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value is not supported
* In addition to the values above, one or more of the following values can be specified to modify the behavior of the function
#DEFINE CRYPT_STRING_NOCRLF 0x40000000 && Do not append any new line characters to the encoded string. The default behavior is to use a carriage return/line feed (CR/LF) pair (0x0D/0x0A) to represent a new line. Windows Server 2003 and Windows XP: This value is not supported
#DEFINE CRYPT_STRING_NOCR 0x80000000 && Only use the line feed (LF) character (0x0A) for a new line. The default behavior is to use a CR/LF pair (0x0D/0x0A) to represent a new line
DECLARE INTEGER CryptBinaryToString IN Crypt32;
STRING @pbBinary,;
LONG cbBinary,;
LONG dwFlags,;
STRING @pszString,;
LONG @pcchString
DECLARE INTEGER GlobalAlloc IN kernel32;
INTEGER wFlags,;
INTEGER dwBytes
DECLARE INTEGER GlobalFree IN kernel32;
INTEGER hMem
DECLARE INTEGER LocalAlloc IN kernel32;
INTEGER uFlags,;
INTEGER uBytes
DECLARE INTEGER LocalFree IN kernel32;
INTEGER hMem
#DEFINE X509_ASN_ENCODING 1 #DEFINE PKCS_7_ASN_ENCODING 0x00010000
CLEAR=DeclarationsApi()lnHandleStore = 0lnHandleStore = CertOpenSystemStore(0, "MY")IF lnHandleStore=0 RETURN .F.ENDIFlpCertContext = 0lpCertContext=CryptUIDlgSelectCertificateFromStore(lnHandleStore, 0, null, null, 1, 0, null)IF lpCertContext=0 RETURN .F.ENDIF
lcOidValue = GetOidValues(lpCertContext, "2.5.29.31", "ARRAY")? "ARRAY: ", lcOidValue ??lcOidValue = GetOidValues(lpCertContext, "2.5.29.31", "URL")? "URL: ", STRTRAN(lcOidValue, "; ", CHR(10))???lcOidValue = GetOidValues(lpCertContext, "1.3.6.1.5.5.7.1.1", "ARRAY")? "ARRAY: ", lcOidValue ??lcOidValue = GetOidValues(lpCertContext, "1.3.6.1.5.5.7.1.1", "URL")? "URL: ", STRTRAN(lcOidValue, "; ", CHR(10))
PROCEDURE GetOidValues() PARAMETERS tpCertContext AS Long, tcOidName AS String, tcRequest AS String lcOidUrl = "" nExtensions = 0 lcCertInfo = "" IF VARTYPE(tpCertContext)="N" lbCertInfo = SUBSTR(SYS(2600, tpCertContext, 20), 13, 4) lcCertInfo = SYS(2600, CTOBIN(lbCertInfo, "4RS"), 112) ENDIF IF !EMPTY(lcCertInfo) cBinaryOid = SUBSTR(lcCertInfo ,105,8) nExtensions = CTOBIN(SUBSTR(cBinaryOid,1,4),"4RS") pRegExtens = CTOBIN(SUBSTR(cBinaryOid,5,4),"4RS") ENDIF IF nExtensions>0 nLenReg=(nExtensions*16) cBlobExtensions = SYS(2600, pRegExtens, nLenReg) lpCertOid = CertFindExtension(tcOidName, nExtensions, cBlobExtensions) IF lpCertOid>0 cOidBinary = SYS(2600, lpCertOid, 16) cOidName = SYS(2600, CTOBIN(SUBSTR(cOidBinary,1,4), "4RS"), 32) nOidType = CTOBIN(SUBSTR(cOidBinary,5,4), "4RS") nOidLenght = CTOBIN(SUBSTR(cOidBinary,9,4), "4RS") cOidValue = SYS(2600, CTOBIN(SUBSTR(cOidBinary,13,4), "4RS"), nOidLenght) lcStructInfo = GetCryptDecodeObjectExString(tcOidName, cOidValue) IF !EMPTY(lcStructInfo) lcOidUrl = GetCryptDecodeToString(tcOidName, cOidValue, lcStructInfo, tcRequest) ENDIF ENDIF ENDIF RETURN lcOidUrlENDPROC
PROCEDURE GetCryptDecodeObjectExString() LPARAMETERS tc_Structure_Name AS String, tc_Structure_Binarys AS String DECLARE LONG CryptDecodeObjectEx IN Crypt32; LONG dwCertEncodingType,; STRING lpszStructType,; STRING pbEncoded,; LONG cbEncoded,; LONG dwFlags,; STRING pDecodePara,; STRING @pvStructInfo,; LONG @pcbStructInfo
dwCertEncodingType = BITOR(PKCS_7_ASN_ENCODING, X509_ASN_ENCODING) lpszStructType = tc_Structure_Name pbEncoded = tc_Structure_Binarys cbEncoded = LEN(pbEncoded) pbKeyBlob = "" cbKeyBlob = 0 nResp=CryptDecodeObjectEx(dwCertEncodingType, @lpszStructType, pbEncoded, cbEncoded, 0, NULL, NULL, @cbKeyBlob) IF cbKeyBlob>0 pbKeyBlob = SPACE(cbKeyBlob) nResp=CryptDecodeObjectEx(dwCertEncodingType, @lpszStructType, pbEncoded, cbEncoded, 0, NULL, @pbKeyBlob, @cbKeyBlob) ENDIF RETURN pbKeyBlobENDPROC
PROCEDURE GetCryptDecodeToString() LPARAMETERS tcExtension AS String, tcExtValue AS String, pvStructInfo AS String, tcRequest AS String lcReturnStr="" DO CASE CASE tcExtension="2.5.29.31" *----- Puntos de distribución CRL, CRL_DIST_POINTS_INFO lcReturnStr = GetStructure_CrlDistPoint(pvStructInfo, tcRequest) CASE tcExtension=="1.3.6.1.5.5.7.1.1" *----- Acceso a la infomración de entidad emisora (CERT_AUTHORITY_INFO_ACCESS) lcReturnStr = GetStructure_CertAuthorityInfoAccess(pvStructInfo, tcRequest) OTHERWISE ENDCASE RETURN lcReturnStrENDPROC
PROCEDURE GetStructure_CrlDistPoint() LPARAMETERS tcCrlDistPoint AS String, tcRequest AS String IF VARTYPE(tcCrlDistPoint)<>"C" RETURN "" ENDIF IF EMPTY(tcCrlDistPoint) RETURN "" ENDIF lcReturnURL = "" lcReturnCRL = "CRL distribution points: " + "; " *----- Número de elementos en la matriz de miembros rgDistPoint, CRL_DIST_POINTS_INFO(cDistPoint, rgDistPoint) nDistPoint = CTOBIN(SUBSTR(tcCrlDistPoint,1,4), "4RS") rgDistPoint = CTOBIN(SUBSTR(tcCrlDistPoint,5,4), "4RS") nIniChr = 5 nIniSub = (nDistPoint * 32)+5 FOR nDP = 1 TO nDistPoint lcReturnCRL = lcReturnCRL + "[" + TRANSFORM(nDP) + "] CRL distribution point: " + "; " *----- CRL_DIST_POINT structure - CERT_ALT_NAME_INFO structure - CRL_DIST_POINT_NAME nDistPointName = CTOBIN(SUBSTR(tcCrlDistPoint, nIniChr+4, 4), "4RS") nAltEntry = CTOBIN(SUBSTR(tcCrlDistPoint, nIniChr+8, 4), "4RS") rgAltEntry = STRCONV(SUBSTR(tcCrlDistPoint, nIniChr+12, 4), 15) nReasonFlags = CTOBIN(SUBSTR(tcCrlDistPoint, nIniChr+16, 4), "4RS") nCRLIssuer = CTOBIN(SUBSTR(tcCrlDistPoint, nIniChr+20, 4), "4RS") nDistPointNameChoice = CTOBIN(SUBSTR(tcCrlDistPoint, nIniChr+24, 4), "4RS") nFullName = CTOBIN(SUBSTR(tcCrlDistPoint, nIniChr+28, 4), "4RS") cUnusedBits = CTOBIN(SUBSTR(tcCrlDistPoint, nIniChr+32, 4), "4RS") DIMENSION aMatDistPoint(nAltEntry,2) nIniChr = nIniChr + 32 FOR nAE = 1 TO nAltEntry nAltNameChoice = CTOBIN(SUBSTR(tcCrlDistPoint, nIniSub+4, 4), "4RS") nAltNameLenght = 0 IF nAltNameChoice=1 OR nAltNameChoice=5 nIniSub = nIniSub + 4 nAltNameLenght = CTOBIN(SUBSTR(tcCrlDistPoint, nIniSub+4, 4), "4RS") ENDIF cHexaAddres = STRCONV(SUBSTR(tcCrlDistPoint, nIniSub+8, 4),15) cHexaSeparator = STRCONV(SUBSTR(tcCrlDistPoint, nIniSub+12, 4),15) nIniSub = nIniSub + IIF(cHexaSeparator="20202020", 12, 8) aMatDistPoint(nAE, 1)=nAltNameChoice aMatDistPoint(nAE, 2)=nAltNameLenght NEXT IF nAltNameChoice=1 OR nAltNameChoice=5 nIniSub = nIniSub + 4 ENDIF cHexaSeparator = STRCONV(SUBSTR(tcCrlDistPoint, nIniSub, 4),15) DO WHILE cHexaSeparator="20202020" nIniSub = nIniSub + 4 cHexaSeparator = STRCONV(SUBSTR(tcCrlDistPoint, nIniSub, 4),15) ENDDO cBlobCRL = SUBSTR(tcCrlDistPoint, nIniSub) FOR nAE = 1 TO (ALEN(aMatDistPoint)/2) DO CASE CASE aMatDistPoint(nAE, 1)=7 cAltNameChoice = SUBSTR(cBlobCRL, 1, AT(CHR(0)+CHR(0), cBlobCRL)+2) lcUrl = ALLTRIM(STRTRAN(cAltNameChoice, CHR(0), "")) cNameCRL = "Name URL = ; " + lcUrl + "; " lcReturnURL = lcReturnURL + IIF(".crl"$LOWER(lcUrl), lcUrl + "; ", "") CASE aMatDistPoint(nAE, 1)=5 cAltNameChoice = SUBSTR(cBlobCRL, 1, aMatDistPoint(nAE, 2)) cNameCRL = "Directory Name: " + CHR(13) + GetStructure_CertNameBlob(null, cAltNameChoice) + "; " ENDCASE nLenght = LEN(cAltNameChoice) + IIF(4-MOD(LEN(cAltNameChoice),4)=4, 0, 4-MOD(LEN(cAltNameChoice),4)) + 1 cHexaSeparator = STRCONV(SUBSTR(cBlobCRL, nLenght, 4),15) cBlobCRL = SUBSTR(cBlobCRL, nLenght + IIF(cHexaSeparator="20202020", 4, 0)) nIniSub = nIniSub + nLenght - IIF(cHexaSeparator="20202020", 1, 5) lcReturnCRL = lcReturnCRL + cNameCRL + "; " NEXT NEXT IF VARTYPE(tcRequest)=="C" lcReturnCRL = IIF(tcRequest="URL", lcReturnURL, lcReturnCRL) ENDIF RETURN lcReturnCRLENDPROC
PROCEDURE GetStructure_CertAuthorityInfoAccess() LPARAMETERS tcAuthorityInfo AS String, tcRequest AS String *----- Acceso a la infomración de entidad emisora (CERT_AUTHORITY_INFO_ACCESS) IF VARTYPE(tcAuthorityInfo)<>"C" RETURN "" ENDIF IF EMPTY(tcAuthorityInfo) RETURN "" ENDIF lcReturnAuthoInfo = "" lcReturnURL = "" *----- Numero de elementos en Array nAccDescr = CTOBIN(SUBSTR(tcAuthorityInfo,1,4), "4RS") *----- Puntero de Origen nPoint00 = CTOBIN(SUBSTR(tcAuthorityInfo,5,4), "4RS") nIniStr = 5 FOR nAIA = 1 TO nAccDescr *----- Puntero de Origen nPoint01 = CTOBIN(SUBSTR(tcAuthorityInfo, nIniStr+4, 4), "4RS") *----- Tipo de Entrada nPoint02 = CTOBIN(SUBSTR(tcAuthorityInfo, nIniStr+8, 4), "4RS") *----- Puntero de Origen nPoint03 = CTOBIN(SUBSTR(tcAuthorityInfo, nIniStr+12, 4), "4RS") *----- Separador de región nPoint04 = CTOBIN(SUBSTR(tcAuthorityInfo, nIniStr+16, 4), "4RS") nIniStr = nIniStr + 16 NEXT nIniStr = nIniStr + 4 cbAutInfo = SUBSTR(tcAuthorityInfo, nIniStr) lcReturnAuthoInfo = "Access to the issuer entity information: ; " FOR DPN = 1 TO nAccDescr lcReturnAuthoInfo = lcReturnAuthoInfo + "[ " + TRANSFORM(DPN) + "] Access to authority information " + "; " nEndBit = AT(REPLICATE(CHR(0),3), cbAutInfo) IF nEndBit==0 lcAutInfo = ALLTRIM(SUBSTR(cbAutInfo, 1)) cbAutInfo = SUBSTR(cbAutInfo, LEN(lcAutInfo)) ELSE lcAutInfo = ALLTRIM(SUBSTR(cbAutInfo, 1, nEndBit-1)) cbAutInfo = SUBSTR(cbAutInfo, AT(lcAutInfo, cbAutInfo) + LEN(lcAutInfo)) ENDIF IF !EMPTY(lcAutInfo) lcMetAcce = "Access method = " + SUBSTR(lcAutInfo, 1, AT(CHR(0), lcAutInfo)-1) + "; " lcAltName = "Alternative name: ; " lcUrlStr = STRCONV(ALLTRIM(SUBSTR(lcAutInfo, AT(CHR(0), lcAutInfo)+1)) + CHR(0), 6) lcAltName = lcAltName + + "URL = " + lcUrlStr lcAutInfo = lcMetAcce + lcAltName +"; " lcReturnURL = lcReturnURL + lcUrlStr + "; " ENDIF lcReturnAuthoInfo = lcReturnAuthoInfo + lcAutInfo + "; " cbAutInfo = GetCleanStringInit(cbAutInfo) NEXT IF VARTYPE(tcRequest)=="C" lcReturnAuthoInfo = IIF(tcRequest="URL", lcReturnURL, lcReturnAuthoInfo) ENDIF RETURN lcReturnAuthoInfoENDPROC
PROCEDURE GetStructure_CertNameBlob() LPARAMETERS tcNameBlob AS String, tcStringBinary AS String lcIssuerStr="" IF VARTYPE(tcNameBlob)="C" lcIssuerByte = 0h + tcNameBlob pbCert_Name_Blob = HeapAlloc(GetProcessHeap(), 0, LEN(lcIssuerByte)) RtlMoveMemory(pbCert_Name_Blob, @lcIssuerByte, LEN(lcIssuerByte)) lcIssuerStr = GetCertNameToString(pbCERT_NAME_BLOB) HeapFree(GetProcessHeap(), 0, pbCert_Name_Blob) ENDIF IF EMPTY(lcIssuerStr) AND !EMPTY(tcStringBinary) cbData = LEN(tcStringBinary) lbIssuer = SUBSTR(tcStringBinary, 1, cbData) pbData = HeapAlloc(GetProcessHeap(), 0, cbData) RtlMoveMemory(pbData, @lbIssuer, cbData) lcIssuerByte = 0h + BINTOC(cbData,"4RS") + BINTOC(pbData, "4RS") pbCert_Name_Blob = HeapAlloc(GetProcessHeap(), 0, LEN(lcIssuerByte)) RtlMoveMemory(pbCert_Name_Blob, @lcIssuerByte, LEN(lcIssuerByte)) lcIssuerStr = GetCertNameToString(pbCERT_NAME_BLOB) HeapFree(GetProcessHeap(), 0, pbCert_Name_Blob) HeapFree(GetProcessHeap(), 0, pbData) ENDIF RETURN lcIssuerStrENDPROC
PROCEDURE GetCertNameToString() LPARAMETERS pbCertNameBlob AS Long *----- Valores posibles para wDwStrType, pueden ser la suma de varios SIMPLENAMESTR = 1 OIDNAMESTR = 2 X500NAMESTR = 3 SEMICOLONFLAG = 0x40000000 CRLFFLAG = 0x08000000 NOPLUSFLAG = 0x20000000 NOQUOTINGFLAG = 0x10000000 NAMEREVERSE = 0x02000000 DISABLEIE4UTF8 = 0x00010000 ENABLEPUNYCODE = 0x00200000 *----- Asignamos valores a Parametros nCertEncodTyp = X509_ASN_ENCODING cpName = pbCertNameBlob nDwStrType = BITOR(X500NAMESTR, OIDNAMESTR, NAMEREVERSE, SEMICOLONFLAG) lcNameDecoded = "" lnNameLong = 0 *----- Intento 1, obtenemos longitud de cadena lnNameLong = CertNameToStr(nCertEncodTyp, cpName, nDwStrType, @lcNameDecoded, @lnNameLong) IF lnNameLong <> 0 *----- Intento 2, conociendo longitud de cadena, Obtenemos el nombre decodificado lcNameDecoded= REPLICATE(CHR(0), lnNameLong) CertNameToStr(nCertEncodTyp, cpName, nDwStrType, @lcNameDecoded, @lnNameLong) ENDIF *----- La función devuelve una cadena terminada en nulo, quitamos el CHR(0) que represanta nulo RETURN STRTRAN(lcNameDecoded, CHR(0), "")ENDPROC
PROCEDURE GetCleanStringInit() LPARAMETERS tcStringToCleanInit AS String lnChrIni = 1 FOR nl = 1 TO LEN(tcStringToCleanInit) cChr = STRCONV(SUBSTR(tcStringToCleanInit, nl, 1),15) IF cChr<>"00" AND cChr<>"20" AND cChr<>"1A" lnChrIni = nl EXIT ENDIF NEXT RETURN SUBSTR(tcStringToCleanInit, lnChrIni)ENDPROC
PROCEDURE DeclarationsApi() DECLARE LONG CertOpenSystemStore IN Crypt32; STRING hprov,; STRING szSubsystemProtocol
DECLARE LONG CertCloseStore IN Crypt32; LONG hCertStore,; LONG dwFlags DECLARE LONG CryptUIDlgSelectCertificateFromStore IN Cryptui; LONG hCertStore,; LONG hWnd, ; STRING @pwszTitle, ; STRING @pwszDisplayString, ; LONG dwDontUseColumn, ; LONG dwFlags,; STRING pvReserved DECLARE LONG CertFindExtension IN Crypt32; STRING pszObjId,; LONG nExtensions,; STRING rgExtensions DECLARE LONG CertNameToStr IN Crypt32; LONG dwCertEncodingType, ; LONG pName, ; LONG dwStrType, ; STRING @psz, ; LONG csz 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
Aquí un par de capturas del código ejecutándose y devolviendo resultado. Use dos certificados, uno nacional del Banco Central del Ecuador emitido para usuario final (MY), y otro de Microsoft de tipo CA.
Saludos,
Fernando
#DEFINE URL_OID_CERTIFICATE_CRL_DIST_POINT 2#DEFINE URL_OID_CERTIFICATE_CRL_DIST_POINT_AND_OCSP 11#DEFINE CRYPT_GET_URL_FROM_EXTENSION 2
CLEAR=DeclarationsApi()lnHandleStore = 0lnHandleStore = CertOpenSystemStore(0, "MY")IF lnHandleStore=0 RETURN .F.ENDIFlpCertContext = 0lpCertContext=CryptUIDlgSelectCertificateFromStore(lnHandleStore, 0, null, null, 1, 0, null)IF lpCertContext=0 RETURN .F.ENDIF
pszUrlOid = URL_OID_CERTIFICATE_CRL_DIST_POINT_AND_OCSP pvPara = lpCertContextdwFlags = CRYPT_GET_URL_FROM_EXTENSIONpUrlArray = NULLpcbUrlArray = 0pUrlInfo = NULLpcbUrlInfo = 0pvReserved = 0nResp = CryptGetObjectUrl(@pszUrlOid, pvPara, dwFlags, pUrlArray, @pcbUrlArray, pUrlInfo, @pcbUrlInfo, pvReserved)IF nResp>0 pUrlArray = SPACE(pcbUrlArray) pUrlInfo = SPACE(pcbUrlInfo) CryptGetObjectUrl(@pszUrlOid, pvPara, dwFlags, @pUrlArray, @pcbUrlArray, @pUrlInfo, @pcbUrlInfo, pvReserved) ? "URL ARRAY: ", STRCONV(pUrlArray,6) ? ? "URL INFO: ", pUrlInfoENDIFCertFreeCertificateContext(lpCertContext)CertCloseStore(lnHandleStore, 0)
PROCEDURE DeclarationsApi() DECLARE LONG CertOpenSystemStore IN Crypt32; STRING hprov,; STRING szSubsystemProtocol
DECLARE LONG CertCloseStore IN Crypt32; LONG hCertStore,; LONG dwFlags
DECLARE LONG CertFreeCertificateContext IN Crypt32; LONG pCertContext
DECLARE LONG CryptUIDlgSelectCertificateFromStore IN Cryptui; LONG hCertStore,; LONG hWnd, ; STRING @pwszTitle, ; STRING @pwszDisplayString, ; LONG dwDontUseColumn, ; LONG dwFlags,; STRING pvReserved
DECLARE LONG CryptGetObjectUrl IN Cryptnet; LONG pszUrlOid,; LONG pvPara,; LONG dwFlags,; STRING @pUrlArray,; LONG @pcbUrlArray,; STRING @pUrlInfo,; LONG @pcbUrlInfo,; LONG pvReserved
ENDPROC
Hola Roman. Si, luego de pasar por java y csharp, decidí desarrollar una librería 100% fox, que al igual que csharp y C++, use al máximo CNG de Windows, para el tema criptográfico. Esto abarca todas las necesidades de firmado de Xml, cifrado y descifrado de datos (asimétrico, simétrico), codificación y decodificación de certificados, importación y exportación de certificados, pares de claves, en diversos formatos (cer,pem,key,pfx,p12,) etc. Uso Long (64 bits) en lugar de Integer (32 bits) por dos razones, mejor rendimiento, y simplificar la asignación de parámetros de las funciones. Usando Long y String no te haces lio y da buenos resultados. Mis aplicaciones las tengo instalada en clientes que usan desde Windows 7 32 bits SP1 hasta Windows 10 64 bits, todos trabajan sin problemas. En este momento estoy trabajando en cifrado RSA, AES, DES, 3DES, estoy en fase de pruebas. Has usado las funciones de BCrypt para hacer cifrados AES? necesito ayuda para cifrar archivos grandes. Mi código aún no es estable en esa parte.
DECLARE LONG CertCreateCertificateContext IN Crypt32; LONG dwCertEncodingType,; STRING pbCertEncoded,; LONG cbCertEncoded
DECLARE LONG CertFreeCertificateContext IN Crypt32; LONG pCertContext
#DEFINE X509_ASN_ENCODING 1#DEFINE PKCS_7_ASN_ENCODING 0x00010000
TEXT TO lcCertB64 TEXTMERGE ADDITIVE NOSHOWMIICLDCCAZWgAwIBAgIQRjRrx4AAVrwR024uxBCzsDANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQD EwdDYXJsUlNBMB4XDTk5MDkxOTAxMDg0N1oXDTM5MTIzMTIzNTk1OVowEzERMA8GA1UEAxMIQWxp Y2VSU0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOCJczmN2PX16Id2OX9OsAW7U4PeD7er 3H3HdSkNBS5tEt+mhibU0m+qWCn8l+z6glEPMIC+sVCeRkTxLLvYMs/GaG8H2bBgrL7uNAlqE/X3 BQWT3166NVbZYf8Zf8mB5vhs6odAcO+sbSx0ny36VTq5mXcCpkhSjE7zVzhXdFdfAgMBAAGjgYEw fzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIGwDAfBgNVHSMEGDAWgBTp4JAnrHggeprTTPJC N04irp44uzAdBgNVHQ4EFgQUd9K00bdMioqjzkWdzuw8oDrj/1AwHwYDVR0RBBgwFoEUQWxpY2VS U0FAZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADgYEAPnBHqEjME1iPylFxa042GF0EfoCxjU3M yqOPzH1WyLzPbrMcWakgqgWBqE4lradwFHUv9ceb0Q7pY9Jkt8ZmbnMhVN/0uiVdfUnTlGsiNnRz uErsL2Tt0z3Sp0LF6DeKtNufZ+S9n/n+dO/q+e5jatg/SyUJtdgadq7rm9tJsCI=ENDTEXT
lnCertContext = GetCertCreateCertificateContext(lcCertB64)IF lnCertContext>0 ? "Aquí esta su puntero al contexto del certificado: " + TRANSFORM(lnCertContext) *----- No olvide liberar el puntero luego de utilizar el certificado CertFreeCertificateContext(lnCertContext)ENDIF
*---- Función que devuelve un puntero al contexto de un certificado codificado, pasar la cadena en b64 please.PROCEDURE GetCertCreateCertificateContext() PARAMETERS tcCertEncodedB64 AS String pCertContext = 0 IF !EMPTY(tcCertEncodedB64) dwCertEncodingType = BITOR(PKCS_7_ASN_ENCODING, X509_ASN_ENCODING) pbCertEncoded = STRCONV(ALLTRIM(STRTRAN(tcCertEncodedB64, CHR(0), "")),14) cbCertEncoded = LEN(pbCertEncoded) pCertContext = CertCreateCertificateContext(dwCertEncodingType, pbCertEncoded, cbCertEncoded) ENDIF RETURN pCertContextENDPROC
#DEFINE URL_OID_CERTIFICATE_CRL_DIST_POINT 2
#DEFINE URL_OID_CERTIFICATE_CRL_DIST_POINT_AND_OCSP 11
#DEFINE CRYPT_GET_URL_FROM_EXTENSION 2
#DEFINE X509_ASN_ENCODING 1
#DEFINE PKCS_7_ASN_ENCODING 0x00010000
#DEFINE CRYPT_STRING_BASE64 0x00000001 && Base64, without headers.
#DEFINE CERT_SHA1_HASH_PROP_ID 3 && Returns the SHA1 hash.
#DEFINE CRYPT_STRING_HEX 0x00000004 && Hexadecimal only format.
* https://cpdn.cryptopro.ru/content/csp40/html/group___pro_c_s_p_ex_DP8.html
#DEFINE szOID_CP_GOST_R3411_R3410EL "1.2.643.2.2.3" && Algorythm GOST R 34.10-2001
#DEFINE szOID_CP_GOST_R3411_12_256_R3410 "1.2.643.7.1.1.3.2" && Algorythm GOST R 34.10-2012, 256 bit
#DEFINE szOID_CP_GOST_R3411_12_512_R3410 "1.2.643.7.1.1.3.3" && Algorythm GOST R 34.10-2012, 512 bit
DECLARE INTEGER CryptStringToBinary IN crypt32;
STRING @pszString,;
LONG cchString,;
LONG dwFlags,;
STRING @pbBinary,;
LONG @pcbBinary,;
LONG pdwSkip,;
LONG pdwFlags
DECLARE LONG CertCreateCertificateContext IN Crypt32;
LONG dwCertEncodingType,;
STRING pbCertEncoded,;
LONG cbCertEncoded
DECLARE LONG CertFreeCertificateContext IN Crypt32;
LONG pCertContext
DECLARE LONG CertOpenSystemStore IN Crypt32;
STRING hprov,;
STRING szSubsystemProtocol
DECLARE LONG CertCloseStore IN Crypt32;
LONG hCertStore,;
LONG dwFlags
DECLARE LONG CertFreeCertificateContext IN Crypt32;
LONG pCertContext
DECLARE LONG CryptUIDlgSelectCertificateFromStore IN Cryptui;
LONG hCertStore,;
LONG hWnd, ;
STRING @pwszTitle, ;
STRING @pwszDisplayString, ;
LONG dwDontUseColumn, ;
LONG dwFlags,;
STRING pvReserved
DECLARE LONG CryptGetObjectUrl IN Cryptnet;
LONG pszUrlOid,;
LONG pvPara,;
LONG dwFlags,;
STRING @pUrlArray,;
LONG @pcbUrlArray,;
STRING @pUrlInfo,;
LONG @pcbUrlInfo,;
LONG pvReserved
DECLARE INTEGER CryptBinaryToString IN Crypt32;
STRING @pbBinary,;
LONG cbBinary,;
LONG dwFlags,;
STRING @pszString,;
LONG @pcchString
DECLARE INTEGER CertGetCertificateContextProperty IN crypt32;
INTEGER pCertContext,;
LONG dwPropId,;
INTEGER pvPara,;
LONG @ pcbData
DECLARE INTEGER CertOIDToAlgId IN crypt32;
STRING @ pszObjId
DECLARE INTEGER LocalAlloc IN kernel32;
INTEGER uFlags,;
INTEGER uBytes
DECLARE INTEGER LocalFree IN kernel32;
INTEGER hMem
DECLARE INTEGER GetLastError ;
IN WIN32API AS GetLastError
DECLARE INTEGER lstrlen IN kernel32;
INTEGER lpString
TEXT TO lcCertB64 TEXTMERGE ADDITIVE NOSHOW
MIIIjTCCCDygAwIBAgIRAZe4dS0WrMSA6BEUsUB9qOYwCAYGKoUDAgIDMIHuMR4wHAYJKoZIhvcN
AQkBFg91Y2ZvbXNAZmZvbXMucnUxGDAWBgUqhQNkARINMTAyNzczOTcxMjg1NzEaMBgGCCqFAwOB
AwEBEgwwMDc3MjcwMzIzODIxCzAJBgNVBAYTAlJVMRgwFgYDVQQIDA83NyDQnNC+0YHQutCy0LAx
FTATBgNVBAcMDNCc0L7RgdC60LLQsDEyMDAGA1UECQwp0J3QvtCy0L7RgdC70L7QsdC+0LTRgdC6
0LDRjyDRg9C7Liwg0LQuMzcxETAPBgNVBAoMCNCk0J7QnNChMREwDwYDVQQDDAjQpNCe0JzQoTAe
Fw0xODA5MDUxMzU2MzdaFw0xOTEyMDUxNDA2MzdaMIIBlzEaMBgGCCqFAwOBAwEBEgwwMDY4MzEw
MDAyNjUxGDAWBgUqhQNkARINMTAyNjgwMTE1ODgxMjEbMBkGCSqGSIb3DQEJARYMdGZvbXNAdG1i
LnJ1MQswCQYDVQQGEwJSVTEsMCoGA1UECAwj0KLQsNC80LHQvtCy0YHQutCw0Y8g0L7QsdC70LDR
gdGC0YwxFTATBgNVBAcMDNCi0LDQvNCx0L7QsjErMCkGA1UECQwi0YPQuy4g0JrQvtC80LzRg9C9
0LDQu9GM0L3QsNGPLCAxODE3MDUGA1UECgwu0KLQpNCe0JzQoSDQotCw0LzQsdC+0LLRgdC60L7Q
uSDQvtCx0LvQsNGB0YLQuDFJMEcGA1UECwxA0J7RgtC00LXQuyDQuNC90YTQvtGA0LzQsNGG0LjQ
vtC90L3QvtCz0L4g0L7QsdC10YHQv9C10YfQtdC90LjRjzE/MD0GA1UEAww20JDQmNChINCf0KMg
0J7QnNChINCi0LDQvNCx0L7QstGB0LrQvtC5INC+0LHQu9Cw0YHRgtC4MGMwHAYGKoUDAgITMBIG
ByqFAwICJAAGByqFAwICHgEDQwAEQJClKMdUgM0jjkBUJzW+mGmTF26Gmgcvk1LbPwllgCg5FxzN
HqF7k3CmIawgTzWyMhIsdCCQHSu9HTdGhZ5NtZejggUFMIIFATAOBgNVHQ8BAf8EBAMCA/gwHQYD
VR0OBBYEFM9X1n2LqtthzFr7YScF5TyaY5shMDMGCSsGAQQBgjcVBwQmMCQGHCqFAwICMgEJyZlh
lao6hJGWT4WgsXOD13KDtj4CAQECAQAwggGGBgNVHSMEggF9MIIBeYAUFbdV5IiKzBbjPrBbebba
8+cNX/ehggFSpIIBTjCCAUoxHjAcBgkqhkiG9w0BCQEWD2RpdEBtaW5zdnlhei5ydTELMAkGA1UE
BhMCUlUxHDAaBgNVBAgMEzc3INCzLiDQnNC+0YHQutCy0LAxFTATBgNVBAcMDNCc0L7RgdC60LLQ
sDE/MD0GA1UECQw2MTI1Mzc1INCzLiDQnNC+0YHQutCy0LAsINGD0LsuINCi0LLQtdGA0YHQutCw
0Y8sINC0LiA3MSwwKgYDVQQKDCPQnNC40L3QutC+0LzRgdCy0Y/Qt9GMINCg0L7RgdGB0LjQuDEY
MBYGBSqFA2QBEg0xMDQ3NzAyMDI2NzAxMRowGAYIKoUDA4EDAQESDDAwNzcxMDQ3NDM3NTFBMD8G
A1UEAww40JPQvtC70L7QstC90L7QuSDRg9C00L7RgdGC0L7QstC10YDRj9GO0YnQuNC5INGG0LXQ
vdGC0YCCCwD0Z+EyAAAAAAJqMCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcDBAYIKwYBBQUH
AwEwMwYJKwYBBAGCNxUKBCYwJDAKBggrBgEFBQcDAjAKBggrBgEFBQcDBDAKBggrBgEFBQcDATAd
BgNVHSAEFjAUMAgGBiqFA2RxATAIBgYqhQNkcQIwggFDBgUqhQNkcASCATgwggE0DDTQodCa0JfQ
mCAi0JrRgNC40L/RgtC+0J/RgNC+IENTUCIgKNCy0LXRgNGB0LjRjyA0LjApDFrQn9CQ0JogItCj
0LTQvtGB0YLQvtCy0LXRgNGP0Y7RidC40Lkg0YbQtdC90YLRgCAi0JrRgNC40L/RgtC+0J/RgNC+
INCj0KYiINCy0LXRgNGB0LjQuCAyLjAMT9Ch0LXRgNGC0LjRhNC40LrQsNGCINGB0L7QvtGC0LLQ
tdGC0YHRgtCy0LjRjyDihJYg0KHQpC8xMjQtMjg2NCDQvtGCIDIwLjAzLjIwMTYMT9Ch0LXRgNGC
0LjRhNC40LrQsNGCINGB0L7QvtGC0LLQtdGC0YHRgtCy0LjRjyDihJYg0KHQpC8xMjgtMjk4MyDQ
vtGCIDE4LjExLjIwMTYwLAYFKoUDZG8EIwwh0KHQmtCX0JggItCa0YDQuNC/0YLQvtCf0YDQviBD
U1AiMFgGA1UdHwRRME8wTaBLoEmGR2h0dHA6Ly91Y2ZvbXMuZmZvbXMucnUvY2RwLzE1Yjc1NWU0
ODg4YWNjMTZlMzNlYjA1Yjc5YjZkYWYzZTcwZDVmZjcuY3JsMIGXBggrBgEFBQcBAQSBijCBhzAw
BggrBgEFBQcwAYYkaHR0cDovL3VjZm9tcy5mZm9tcy5ydS9vY3NwL29jc3Auc3JmMFMGCCsGAQUF
BzAChkdodHRwOi8vdWNmb21zLmZmb21zLnJ1L2FpYS8xNWI3NTVlNDg4OGFjYzE2ZTMzZWIwNWI3
OWI2ZGFmM2U3MGQ1ZmY3LmNydDArBgNVHRAEJDAigA8yMDE4MDkwNTEzNTYzN1qBDzIwMTkwOTA1
MTM1NjM3WjAIBgYqhQMCAgMDQQB5goLR7QDXU6ZtYraFLA8KpEPBlDOXhgRxsZwRZNvyfoshn9+Z
KOYIaFyw5lc7/PwRgyq/XmAf3iZ7ObUdeN7i
ENDTEXT
m.lcCertB64 = StrTran(m.lcCertB64, ' ', '') && Very actual in some cases!
lnCertContext = 0
If !Empty(lcCertB64)
nBufsize=0
= CryptStringToBinary(@lcCertB64, LEN(m.lcCertB64), CRYPT_STRING_BASE64, NULL, @nBufsize, 0,0)
pbCertEncoded = REPLICATE(CHR(0), m.nBufsize)
nResp = CryptStringToBinary(@lcCertB64, LEN(m.lcCertB64), CRYPT_STRING_BASE64, @pbCertEncoded, @nBufsize, 0,0)
dwCertEncodingType = BITOR(PKCS_7_ASN_ENCODING, X509_ASN_ENCODING)
cbCertEncoded = LEN(pbCertEncoded)
lnCertContext = CertCreateCertificateContext(dwCertEncodingType, pbCertEncoded, cbCertEncoded)
EndIf
If lnCertContext=0
=MessageBox("lnCertContext = 0",64,"Error")
Return .F.
EndIf
lcStr = ""
lcCERT_CONTEXT = SYS(2600, lnCertContext, 20)
pCertInfo = CTOBIN(SubStr(lcCERT_CONTEXT, 13, 4), "4RS")
lcCERT_INFO = SYS(2600, pCertInfo, 112)
pAlgorithmOID = CTOBIN(SubStr(lcCERT_INFO, 13, 4), "4RS")
lnStrLen = lstrlen(pAlgorithmOID)
lcAlgorithmOID = SYS(2600, pAlgorithmOID, lnStrLen)
Do Case
Case lcAlgorithmOID == szOID_CP_GOST_R3411_R3410EL && "1.2.643.2.2.3"
lcStr = "Algorythm GOST R 34.10-2001"
Case lcAlgorithmOID == szOID_CP_GOST_R3411_12_256_R3410 && "1.2.643.7.1.1.3.2"
lcStr = "Algorythm GOST R 34.10-2012, 256 bit"
Case lcAlgorithmOID == szOID_CP_GOST_R3411_12_512_R3410 && "1.2.643.7.1.1.3.3"
lcStr = "Algorythm GOST R 34.10-2012, 512 bit"
EndCase
lnCALG_GR3411 = CertOIDToAlgId(@lcAlgorithmOID) && CALG_GR3411 = 32798, CALG_GR3411_2012_256 = 32801, CALG_GR3411_2012_512 = 32802
=MessageBox(lcStr,64,"Algorythm")
* Get the certificate thumbprint (SHA1 hash)
m.lGetProperty = .T.
m.pcbData = 0
If !CertGetCertificateContextProperty(lnCertContext, CERT_SHA1_HASH_PROP_ID, 0, @m.pcbData) = 0
pvData = LocalAlloc(0x0040, m.pcbData)
If !CertGetCertificateContextProperty(lnCertContext, CERT_SHA1_HASH_PROP_ID, pvData, @m.pcbData) = 0
m.lcHashSha1 = SYS(2600, pvData, m.pcbData)
Else
lnResultCode = GetLastError()
lcErr = "Error getting thumbprint"
=MessageBox(lcErr,16,"Error: " + Transform(lnResultCode,"@0"))
m.lGetProperty = .F.
EndIf
Else
lnResultCode = GetLastError()
lcErr = "Error getting thumbprint"
=MessageBox(lcErr,16,"Error: " + Transform(lnResultCode,"@0"))
m.lGetProperty = .F.
EndIf
If m.lGetProperty
nBufSize=0
= CryptBinaryToString(@m.lcHashSha1, Len(m.lcHashSha1), CRYPT_STRING_HEX, NULL, @nBufSize)
lcThumbprint = REPLICATE(CHR(0), m.nBufSize)
If !CryptBinaryToString(@m.lcHashSha1, Len(m.lcHashSha1), CRYPT_STRING_HEX, @lcThumbprint, @nBufSize) = 0
lcThumbprint = StrTran(StrTran(StrTran(lcThumbprint,Chr(13),""),Chr(10),Chr(32)),Chr(32)+Chr(32),Chr(32))
If Right(lcThumbprint, 1) == Chr(0)
lcThumbprint = Left(lcThumbprint, Len(lcThumbprint)-1)
EndIf
lcThumbprint = Upper(AllT(lcThumbprint))
lcStr = "Certificate thumbprint: " + AllT(lcThumbprint)
=MessageBox(AllT(lcThumbprint),64,"Certificate Sha1 hash")
Else
=MessageBox("Can't get the certificate thumbprint!",16,"Error")
EndIf
EndIf
If !Empty(pvData)
LocalFree(pvData)
EndIf
pszUrlOid = URL_OID_CERTIFICATE_CRL_DIST_POINT && URL_OID_CERTIFICATE_CRL_DIST_POINT_AND_OCSP
pvPara = lnCertContext
dwFlags = CRYPT_GET_URL_FROM_EXTENSION
pUrlArray = NULL
pcbUrlArray = 0
pUrlInfo = NULL
pcbUrlInfo = 0
pvReserved = 0
nResp = CryptGetObjectUrl(@pszUrlOid, pvPara, dwFlags, pUrlArray, @pcbUrlArray, pUrlInfo, @pcbUrlInfo, pvReserved)
If nResp>0
pUrlArray = Space(pcbUrlArray)
pUrlInfo = Space(pcbUrlInfo)
If !CryptGetObjectUrl(@pszUrlOid, pvPara, dwFlags, @pUrlArray, @pcbUrlArray, @pUrlInfo, @pcbUrlInfo, pvReserved) = 0
lcCRLArray = STRCONV(pUrlArray,6)
lcStartCDP = AT("http://", lcCRLArray)
lnI = 1
Do While lcStartCDP > 0
lcCRLArray = SubStr(lcCRLArray, lcStartCDP)
lcCDP = Left(lcCRLArray, AT(Chr(0), lcCRLArray)-1)
lcCRLArray = SubStr(lcCRLArray, AT(Chr(0), lcCRLArray)+1)
lcStartCDP = AT("http://", lcCRLArray)
lcStr = "[" + AllT(Str(lnI)) + "] CDP point: " + AllT(lcCDP)
=MessageBox(lcStr,64,"Info")
lnI = lnI + 1
EndDo
Else
=MessageBox("Can't get CRL List URL!",16,"Error")
EndIf
EndIf
CertFreeCertificateContext(lnCertContext)
* CryptQueryObject types and flags
#DEFINE CERT_QUERY_OBJECT_FILE 1
#DEFINE CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED 0x400 && 1024 OR (1 << 10) OR (1 shl 10) OR 2 ^ 10
#DEFINE CERT_QUERY_FORMAT_FLAG_BINARY 0x002 && 2 OR (1 << 1) OR (1 shl 1) OR 2 ^ 1
DECLARE LONG CryptQueryObject IN Crypt32;
LONG dwObjectType,;
STRING pvObject,; && I TRY THIS PARAMETER LONG AND STRING, BUT DON'T WORK...
LONG dwExpectedContentTypeFlags,;
LONG dwExpectedFormatTypeFlags,;
LONG dwFlags,;
LONG @pdwMsgAndCertEncodingType,;
LONG @pdwContentType,;
LONG @pdwFormatType,;
LONG @phCertStore,;
LONG @phMsg,;
LONG @ppvContext
lcCRLFile = "C:\MyFolder\CRL\163d4290bf0a9c881766b9264f928470a3d705db.crl"
If File(lcCRLFile)
dwObjectType = CERT_QUERY_OBJECT_FILE && LONG dwObjectType
pvData = StrConv("file://" + lcCRLFile + CHR(0), 5) && STRING pvData
dwExpectedContentTypeFlags = CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED
dwExpectedFormatTypeFlags = CERT_QUERY_FORMAT_FLAG_BINARY
dwFlags = 0
dwEncoding = 0
dwContentType = 0
dwFormatType = 0
hStore = 0
hMsg = 0
* Get message handle and store handle from the signed file (CRL)
fResult = CryptQueryObject(dwObjectType, pvData, dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags, dwFlags, @dwEncoding, @dwContentType, @dwFormatType, @hStore, @hMsg, 0)
If Empty(fResult)
lnResultCode = GetLastError()
If lnResultCode = -2146885623 && 0x80092009
lcErr = "Cannot find the requested object." && CRYPT_E_NO_MATCH. May be file is not signed? No!
Else
lcErr = "CryptQueryObject error"
EndIf
=MessageBox(lcErr,16,"Error: " + Transform(lnResultCode,"@0"))
EndIf
EndIf
#DEFINE CERT_QUERY_OBJECT_FILE 1#DEFINE CERT_QUERY_CONTENT_CRL 3#DEFINE CERT_QUERY_FORMAT_BINARY 1#DEFINE CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED 10#DEFINE CERT_QUERY_CONTENT_FLAG_CRL BITLSHIFT(1,CERT_QUERY_CONTENT_CRL)#DEFINE CERT_QUERY_FORMAT_FLAG_BINARY BITLSHIFT(1,CERT_QUERY_FORMAT_BINARY)#DEFINE CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED BITLSHIFT(1,CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED)=DeclarationsAPIS()SET STEP ONlcCRLFile = "C:\PROYECTOS\VFPXADES\CERTIFICATES\CRLS\15b755e4888acc16e33eb05b79b6daf3e70d5ff7.crl"IF FILE(lcCRLFile)
dwObjectType = CERT_QUERY_OBJECT_FILE && LONG dwObjectType
pvData = STRCONV(lcCRLFile + CHR(0), 5) && STRING pvData dwExpectedContentTypeFlags = CERT_QUERY_CONTENT_FLAG_CRL
dwExpectedFormatTypeFlags = CERT_QUERY_FORMAT_FLAG_BINARY dwFlags = 0 dwEncoding = 0 dwContentType = 0 dwFormatType = 0 hStore = 0 hMsg = 0
ppvContext = 0 *----- Get message handle and store handle from the signed file (CRL) nResult = CryptQueryObject(dwObjectType, pvData, dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags, dwFlags, @dwEncoding, @dwContentType, @dwFormatType, @hStore, @hMsg, @ppvContext) IF nResult==0 lnResultCode = GetLastError() IF lnResultCode = -2146885623 && 0x80092009
lcErr = "Cannot find the requested object." && CRYPT_E_NO_MATCH. May be file is not signed? No!
ELSE lcErr = "CryptQueryObject error" ENDIF =MESSAGEBOX(lcErr,16,"Error: " + TRANSFORM(lnResultCode,"@0")) ELSE ? "dwEncoding: ", dwEncoding ? "dwContentType: ", dwContentType ? "dwFormatType: ", dwFormatType ? "hStore: ", hStore ? "hMsg: ", hMsg ? "ppvContext: ", ppvContext ENDIFENDIF
PROCEDURE DeclarationsAPIS()
DECLARE LONG CryptQueryObject IN Crypt32; LONG dwObjectType,; STRING pvObject,;
LONG dwExpectedContentTypeFlags,; LONG dwExpectedFormatTypeFlags,; LONG dwFlags,; LONG @pdwMsgAndCertEncodingType,; LONG @pdwContentType,; LONG @pdwFormatType,; LONG @phCertStore,; LONG @phMsg,; LONG @ppvContext
ENDPROC
#DEFINE CRYPT_STRING_BASE64HEADER 0#DEFINE CRYPT_STRING_BASE64 1#DEFINE CRYPT_STRING_BINARY 2#DEFINE CRYPT_STRING_ANY 7
#DEFINE URL_OID_CERTIFICATE_ISSUER 1#DEFINE URL_OID_CERTIFICATE_CRL_DIST_POINT 2
#DEFINE URL_OID_CTL_ISSUER 3#DEFINE URL_OID_CTL_NEXT_UPDATE 4#DEFINE URL_OID_CRL_ISSUER 5#DEFINE URL_OID_CERTIFICATE_FRESHEST_CRL 6#DEFINE URL_OID_CRL_FRESHEST_CRL 7#DEFINE URL_OID_CROSS_CERT_DIST_POINT 8#DEFINE URL_OID_CERTIFICATE_OCSP 9#DEFINE URL_OID_CERTIFICATE_OCSP_AND_CRL_DIST_POINT 10#DEFINE URL_OID_CERTIFICATE_CRL_DIST_POINT_AND_OCSP 11#DEFINE URL_OID_CROSS_CERT_SUBJECT_INFO_ACCESS 12#DEFINE URL_OID_CERTIFICATE_ONLY_OCSP 13
#DEFINE CRYPT_GET_URL_FROM_ANY 0
#DEFINE CRYPT_GET_URL_FROM_PROPERTY 1#DEFINE CRYPT_GET_URL_FROM_EXTENSION 2
#DEFINE CRYPT_GET_URL_FROM_UNAUTH_ATTRIBUTE 4#DEFINE CRYPT_GET_URL_FROM_AUTH_ATTRIBUTE 8
#DEFINE CERT_CONTEXT_REVOCATION_TYPE 1#DEFINE CERT_VERIFY_REV_CHAIN_FLAG 1#DEFINE CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION 2#DEFINE CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG 4
#DEFINE CONTEXT_OID_CERTIFICATE 1#DEFINE CONTEXT_OID_CRL 2#DEFINE CONTEXT_OID_CTL 3#DEFINE CONTEXT_OID_PKCS7 4#DEFINE CONTEXT_OID_CAPI2_ANY 5#DEFINE CONTEXT_OID_OCSP_RESP 6
#DEFINE CRYPT_RETRIEVE_MULTIPLE_OBJECTS 1#DEFINE CRYPT_CACHE_ONLY_RETRIEVAL 2#DEFINE CRYPT_WIRE_ONLY_RETRIEVAL 4#DEFINE CRYPT_DONT_CACHE_RESULT 8#DEFINE CRYPT_ASYNC_RETRIEVAL 10#DEFINE CRYPT_STICKY_CACHE_RETRIEVAL 4096#DEFINE CRYPT_LDAP_SCOPE_BASE_ONLY_RETRIEVAL 8192#DEFINE CRYPT_OFFLINE_CHECK_RETRIEVAL 16384
#DEFINE X509_ASN_ENCODING 1#DEFINE PKCS_7_ASN_ENCODING 0x00010000
#DEFINE FORMAT_MESSAGE_FROM_SYSTEM 4096
CLEAR=DeclarationsApi()
lnCertContext = GetCertCreateCertificateContext(lcCertB64)IF lnCertContext>0
pszUrlOid = URL_OID_CERTIFICATE_CRL_DIST_POINT pvPara = lnCertContext dwFlags = CRYPT_GET_URL_FROM_ANY
pUrlArray = NULL pcbUrlArray = 0 pUrlInfo = NULL pcbUrlInfo = 0 pvReserved = 0 nResp = CryptGetObjectUrl(@pszUrlOid, pvPara, dwFlags, pUrlArray, @pcbUrlArray, pUrlInfo, @pcbUrlInfo, pvReserved)
IF nResp>0 pUrlArray = SPACE(pcbUrlArray) pUrlInfo = SPACE(pcbUrlInfo)
CryptGetObjectUrl(@pszUrlOid, pvPara, dwFlags, @pUrlArray, @pcbUrlArray, @pUrlInfo, @pcbUrlInfo, pvReserved)
? "URL INFO: ", STRCONV(pUrlInfo,15) nItems = CTOBIN(LEFT(pUrlArray,4), "4RS") nPointer0 = CTOBIN(SUBSTR(pUrlArray, 5,4), "4RS") nIniChr = 5 FOR X = 1 TO nItems nIniChr = nIniChr + 4 cString = STRCONV(SYS(2600, CTOBIN(SUBSTR(pUrlArray,nIniChr,4), "4RS"), 600),6) lcURL = ALLTRIM(SUBSTR(cString, 1, AT(CHR(0), cString)))+CHR(0) ? lcURL ? GetValidityCertInCRL(lcURL, lnCertContext) NEXT ENDIF CertFreeCertificateContext(lnCertContext)ENDIF
PROCEDURE GetCertCreateCertificateContext() PARAMETERS tcCertEncodedB64 AS String pCertContext = 0 IF !EMPTY(tcCertEncodedB64) dwCertEncodingType = BITOR(PKCS_7_ASN_ENCODING, X509_ASN_ENCODING)
pbCertEncoded = GetCryptStringToBinary(ALLTRIM(STRTRAN(tcCertEncodedB64, CHR(0), "")))
cbCertEncoded = LEN(pbCertEncoded) pCertContext = CertCreateCertificateContext(dwCertEncodingType, pbCertEncoded, cbCertEncoded) ENDIF RETURN pCertContextENDPROC
PROCEDURE GetCryptStringToBinary() PARAMETERS tcStringCert AS String lcRespStr = "" IF VARTYPE(tcStringCert)=="C" dwBufferLen=0 pdwSkip=0 pdwFlags=0 nResp = CryptStringToBinary(tcStringCert, 0, CRYPT_STRING_ANY, NULL, @dwBufferLen, @pdwSkip, @pdwFlags) pbCertEncoded = SPACE(dwBufferLen) DO CASE CASE pdwFlags=0 *------- Base64, with certificate beginning and ending headers. CryptStringToBinary(tcStringCert, 0, CRYPT_STRING_BASE64HEADER, @pbCertEncoded, @dwBufferLen, @pdwSkip, @pdwFlags) CASE pdwFlags=1 *------- Base64, without headers. CryptStringToBinary(tcStringCert, 0, CRYPT_STRING_BASE64, @pbCertEncoded, @dwBufferLen, @pdwSkip, @pdwFlags) CASE pdwFlags=2 *------- Pure binary copy. pbCertEncoded=tcStringCert ENDCASE lcRespStr = pbCertEncoded ENDIF RETURN lcRespStrENDPROC
PROCEDURE GetValidityCertInCRL() LPARAMETERS tcURL AS String, tpCertContext AS Long pszUrl = tcURL pszObjectOid = CONTEXT_OID_CRL dwRetrievalFlags = CRYPT_WIRE_ONLY_RETRIEVAL dwTimeout = 0 pCrlContext = 0 hAsyncRetrieve = NULL pCredentials = NULL pvVerify = NULL pAuxInfo = NULL nResp = CryptRetrieveObjectByUrlA(pszUrl, @pszObjectOid, dwRetrievalFlags, dwTimeout, @pCrlContext, hAsyncRetrieve, pCredentials, pvVerify, pAuxInfo) ? nResp, IIF(nResp=1, "retrieved Object", "Non Retrieved Object") ? pCrlContext, IIF(pCrlContext>0, "CRL Pointer" , "") IF nResp>0 pTimeToVerify = 0 pCrlInfo = CTOBIN(SYS(2600, pCrlContext+ 12, 4), "4RS") nResp = CertVerifyCRLTimeValidity(pTimeToVerify, pCrlInfo) ? nResp, IIF(nResp=0, "CRL time OK", "CRL time out") IF nResp==0 pCert = tpCertContext pCrlContext = pCrlContext dwFlags = 0 pvReserved = 0 ppCrlEntry = 0 nResp = CertFindCertificateInCRL(pCert, pCrlContext, dwFlags, pvReserved, @ppCrlEntry) ? nResp, IIF(nResp=1, "Certificate searched", "Certificate non searched") IF nResp=1 ? ppCrlEntry, IIF(ppCrlEntry=0, "CERTIFICATE OK", "CERTIFICATE REVOCATE") ENDIF CertFreeCRLContext(pCrlContext) ELSE =GetMessageError() ENDIF ELSE =GetMessageError() ENDIFENDPROC
PROCEDURE GetMessageError(tnNumError AS Long) IF VARTYPE(tnNumError)=="N" lnErrorCode = tnNumError 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 DeclarationsApi() DECLARE LONG CryptStringToBinary IN Crypt32;
STRING @pszString, ; LONG cchString, ; LONG dwFlags,; STRING @pbBinary, ; LONG @pcbBinary,;
LONG @pdwSkip, ; LONG @pdwFlags
DECLARE LONG CertCreateCertificateContext IN Crypt32; LONG dwCertEncodingType,; STRING pbCertEncoded,; LONG cbCertEncoded
DECLARE LONG CryptGetObjectUrl IN CryptNet;
LONG pszUrlOid,; LONG pvPara,; LONG dwFlags,; STRING @pUrlArray,; LONG @pcbUrlArray,; STRING @pUrlInfo,; LONG @pcbUrlInfo,; LONG pvReserved
DECLARE LONG CryptRetrieveObjectByUrlA IN CryptNet; STRING pszUrl,; LONG pszObjectOid,; LONG dwRetrievalFlags,; LONG dwTimeout,; LONG @ppvObject,; STRING hAsyncRetrieve,; STRING pCredentials,; STRING pvVerify,; STRING pAuxInfo
DECLARE LONG CertVerifyCRLTimeValidity IN Crypt32; LONG pTimeToVerify,; LONG pCrlInfo
DECLARE LONG CertFindCertificateInCRL IN Crypt32; LONG pCert,; LONG pCrlContext,; LONG dwFlags,; LONG pvReserved,; LONG @ppCrlEntry
DECLARE LONG CertFreeCertificateContext IN Crypt32; LONG pCertContext
DECLARE LONG CertFreeCRLContext IN Crypt32; LONG pCrlContext
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