Page 1 of 1
How to download SSL certificate from a server
Posted: Sun Nov 04, 2018 10:33 am
by firace
I'm not sure how to download (to file or memory) the SSL certificate from an HTTPS server in PB.
Any ideas?
In Python for instance, that's very simple:
Code: Select all
import ssl
ssl.get_server_certificate(('server.test.com', 443))
Re: How to download SSL certificate from a server
Posted: Sun Nov 04, 2018 11:09 am
by firace
Apparently this could be a way for Windows:
https://blogs.msdn.microsoft.com/jpsand ... in_context
But it looks complicated - to me, at least.
Re: How to download SSL certificate from a server
Posted: Sun Nov 04, 2018 11:23 am
by infratec
In PB it's nearly the same ...
You have to write a wrapper for OpenSSL, then you can use the same function
Or you can use libcurl, but I don't know if you can get all informations:
https://curl.haxx.se/libcurl/c/CURLINFO_CERTINFO.html
You can nearly direct convert this example to PB with our libcurl.pbi
Re: How to download SSL certificate from a server
Posted: Sun Nov 04, 2018 12:22 pm
by infratec
Ups..
I had to add some sructures and definitions to libcurl.pbi
But on windows it results in 0 certs maybe that openssl is not used by the PB libcurl.
I have to check the code on linux.
Re: How to download SSL certificate from a server
Posted: Thu Nov 08, 2018 7:56 pm
by firace
Yes it does seem that the embedded PB libcurl does not support that feature, unfortunately.
So if someone knows how to translate the following MSDN snippet to PB, it would be really great:
Code: Select all
PCCERT_CHAIN_CONTEXT CertCtx=NULL;
DWORD cbCertSize = sizeof(&CertCtx);
//GetCertificate information
if (InternetQueryOption(hReq,INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT ,(LPVOID)&CertCtx,&cbCertSize))
{
//---------------------------------------------------------------
// Display some of the contents of the chain.
PCCERT_CHAIN_CONTEXT pChainContext=CertCtx;
printf("The size of the chain context is %d. \n",pChainContext->cbSize);
printf("%d simple chains found.\n",pChainContext->cChain);
printf("\nError status for the chain:\n");
CERT_SIMPLE_CHAIN *simpleCertificateChainWithinContext = NULL;
for (int i=0; i<pChainContext->cChain; i++)
{
simpleCertificateChainWithinContext=pChainContext->rgpChain[i];
// for each certificate chain in this context...
for (int simpleCertChainIndex = 0;
simpleCertChainIndex < simpleCertificateChainWithinContext->cElement;
simpleCertChainIndex++)
{
// get the CertContext from the array
PCCERT_CONTEXT pCertContext =
simpleCertificateChainWithinContext->rgpElement[simpleCertChainIndex]->pCertContext;
//-------------------------------------------------------------------
// Find and print the name of the subject of the certificate
// just retrieved.
TCHAR pszNameString[256];
if(CertGetNameString(
pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
pszNameString,
128))
{
wprintf(L"Certificate for %s has been retrieved.\n", pszNameString);
}
else
{
wprintf(L"CertGetName failed. \n");
}
// Get the issuer now...
if(CertGetNameString( pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG,
NULL,
pszNameString,
128))
{
wprintf(L"Certificate issuer is %s.\n\n", pszNameString);
}
else
{
wprintf(L"CertGetName failed. \n");
}
}
}
//important! Free the CertCtx
CertFreeCertificateChain(CertCtx);
}
else
{
ErrorOut (GetLastError(), TEXT("HttpQueryInfo"));
}
Re: How to download SSL certificate from a server
Posted: Thu Nov 08, 2018 9:29 pm
by infratec
Hi,
maybe this works a bit (or not)
Code: Select all
#INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT = 105
#CERT_NAME_SIMPLE_DISPLAY_TYPE = 4
#CERT_NAME_ISSUER_FLAG = $00000001
...
removed. See working code below.
Re: How to download SSL certificate from a server
Posted: Fri Nov 09, 2018 10:48 am
by firace
Thanks infratec! I'm impressed at how fast you could convert it, even if it doesn't work yet.
This is my simplified test code. Not sure where it goes wrong...
Code: Select all
#INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT = 105
#CERT_NAME_SIMPLE_DISPLAY_TYPE = 4
#CERT_NAME_ISSUER_FLAG = $00000001
Structure CERT_CONTEXT
dwCertEncodingType.l
*pbCertEncoded.Byte
cbCertEncoded.l
*CertInfo.CERT_INFO
HCERTSTORE.l
EndStructure
Structure CERT_TRUST_STATUS
dwErrorStatus.l
dwInfoStatus.l
EndStructure
Structure CERT_CHAIN_ELEMENT
cbSize.l
*CertContext.CERT_CONTEXT
TrustStatus.CERT_TRUST_STATUS
*RevocationInfo.CERT_REVOCATION_INFO
*IssuanceUsage.CERT_ENHKEY_USAGE
*ApplicationUsage.CERT_ENHKEY_USAGE
*ExtendedErrorInfo
EndStructure
Structure CERT_SIMPLE_CHAIN
cbSize.l
TrustStatus.CERT_TRUST_STATUS
cElement.l
*rgpElement.CERT_CHAIN_ELEMENT[0]
*TrustListInfo.CERT_TRUST_LIST_INFO
fHasRevocationFreshnessTime.i
dwRevocationFreshnessTime.l
EndStructure
Structure CERT_CHAIN_CONTEXT
cbSize.l
TrustStatus.CERT_TRUST_STATUS
cChain.l
*rgpChain.CERT_SIMPLE_CHAIN[0]
cLowerQualityChainContext.l
*rgpLowerQualityChainContext.CERT_CHAIN_CONTEXT
fHasRevocationFreshnessTime.i
dwRevocationFreshnessTime.l
dwCreateFlags.l
ChainId.GUID
EndStructure
Define cbCertSize.l = SizeOf(CERT_CHAIN_CONTEXT);
Define *CertCtx.CERT_CHAIN_CONTEXT
Define *ChainContext.CERT_CHAIN_CONTEXT
Define *simpleCertificateChainWithinContext.CERT_SIMPLE_CHAIN
Define *CertContext.CERT_CONTEXT
Define i.i, simpleCertChainIndex.i
file$ = "https://ipinfo.io/8.8.8.8/org"
#INTERNET_FLAG_RELOAD = $80000000
#INTERNET_OPTION_SECURITY_FLAGS = 31
#SECURITY_FLAG_IGNORE_UNKNOWN_CA = $100
Bytes.l = 0
Html.s = Space(50000)
hInet.l = InternetOpen_("", 0, #Null, #Null, 0)
dwFlags.l = 0
dwBuffLen = SizeOf(dwFlags)
dwFlags = $2000|$1000|$200|$100 ; $800000| |$80
InternetSetOption_(hInet, #INTERNET_OPTION_SECURITY_FLAGS, @dwFlags, SizeOf(dwFlags))
hURL.l = InternetOpenUrl_(hInet, file$, #Null, 0, #INTERNET_FLAG_RELOAD, 0)
InternetReadFile_(hURL, @Html, Len(Html), @Bytes)
html = PeekS(@HTML, Len(HTML), #PB_Ascii)
Debug "HTML: " + html
;
Debug hInet
*CertCtx = AllocateMemory(cbCertSize)
InternetQueryOption_(hInet, #INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT , @*CertCtx, @cbCertSize)
Debug "The size of the chain context is " + Str(*CertCtx\cbSize)
Re: How to download SSL certificate from a server
Posted: Fri Nov 09, 2018 6:55 pm
by infratec
One step further:
Code: Select all
EnableExplicit
#INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT = 105
#CERT_NAME_SIMPLE_DISPLAY_TYPE = 4
#CERT_NAME_ISSUER_FLAG = $00000001
...
removed. See working code below.
Re: How to download SSL certificate from a server
Posted: Sat Nov 10, 2018 11:33 am
by infratec
I did it:
Code: Select all
EnableExplicit
#INTERNET_FLAG_RELOAD = $80000000
#INTERNET_OPTION_SECURITY_FLAGS = 31
#INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT = 105
#SECURITY_FLAG_IGNORE_UNKNOWN_CA = $100
#CERT_NAME_SIMPLE_DISPLAY_TYPE = 4
#CERT_NAME_ISSUER_FLAG = $00000001
Structure CERT_CONTEXT Align #PB_Structure_AlignC
dwCertEncodingType.l
*pbCertEncoded.Byte
cbCertEncoded.l
*CertInfo.CERT_INFO
HCERTSTORE.l
EndStructure
Structure CERT_TRUST_STATUS Align #PB_Structure_AlignC
dwErrorStatus.l
dwInfoStatus.l
EndStructure
Structure CERT_CHAIN_ELEMENT Align #PB_Structure_AlignC
cbSize.l
*CertContext.CERT_CONTEXT
TrustStatus.CERT_TRUST_STATUS
*RevocationInfo.CERT_REVOCATION_INFO
*IssuanceUsage.CERT_ENHKEY_USAGE
*ApplicationUsage.CERT_ENHKEY_USAGE
*ExtendedErrorInfo
EndStructure
Structure CERT_SIMPLE_CHAIN Align #PB_Structure_AlignC
cbSize.l
TrustStatus.CERT_TRUST_STATUS
cElement.l
*rgpElement.CERT_CHAIN_ELEMENT[0]
*TrustListInfo.CERT_TRUST_LIST_INFO
fHasRevocationFreshnessTime.l
dwRevocationFreshnessTime.l
EndStructure
Structure CERT_CHAIN_CONTEXT Align #PB_Structure_AlignC
cbSize.l
TrustStatus.CERT_TRUST_STATUS
cChain.l
*rgpChain.CERT_SIMPLE_CHAIN[0]
cLowerQualityChainContext.l
*rgpLowerQualityChainContext.CERT_CHAIN_CONTEXT
fHasRevocationFreshnessTime.l
dwRevocationFreshnessTime.l
dwCreateFlags.l
ChainId.GUID
EndStructure
Define *CertCtx.CERT_CHAIN_CONTEXT
Define *ChainContext.CERT_CHAIN_CONTEXT
Define *simpleCertificateChainWithinContext.CERT_SIMPLE_CHAIN
Define *CertContext.CERT_CONTEXT
Define.i i, simpleCertChainIndex
Define.l Bytes, hInet, dwFlags, hConnect, hRequest, dwContext, cbCertSize
Define *SimpleChain.CERT_CHAIN_ELEMENT
Define *NameString
Prototype.l Proto_CertGetNameString(*CertContext.CERT_CONTEXT, dwType.l, dwFlags.l, *pvTypePara, *NameString, cchNameString.l)
Prototype Proto_CertFreeCertificateChain(*ChainContext.CERT_CHAIN_CONTEXT)
Global CertGetNameString.Proto_CertGetNameString
Global CertFreeCertificateChain.Proto_CertFreeCertificateChain
If OpenLibrary(0, "crypt32.dll")
CertGetNameString = GetFunction(0, "CertGetNameStringW")
CertFreeCertificateChain = GetFunction(0, "CertFreeCertificateChain")
Else
End
EndIf
hInet = InternetOpen_("", 0, #Null, #Null, 0)
If hInet
hConnect = InternetConnect_(hInet, "ipinfo.io", #INTERNET_DEFAULT_HTTPS_PORT, #Null, #Null, #INTERNET_SERVICE_HTTP, 0, @dwContext)
If hConnect
hRequest = HttpOpenRequest_(hConnect, "GET", "/8.8.8.8/org", #Null, #Null, #Null, #INTERNET_FLAG_SECURE, @dwContext)
If hRequest
If HttpSendRequest_(hRequest, #Null, 0, #Null, 0)
cbCertSize = SizeOf(CERT_CHAIN_CONTEXT)
If InternetQueryOption_(hRequest, #INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT , @*CertCtx, @cbCertSize)
*ChainContext = *CertCtx
Debug "The size of the chain context is " + Str(*ChainContext\cbSize)
Debug Str(*ChainContext\cChain) + " simple chains found."
Debug ""
Debug "Status For the chain(s):"
Debug ""
For i = 0 To *ChainContext\cChain - 1
Debug "Chain " + Str(i + 1)
Debug ""
*simpleCertificateChainWithinContext = PeekL(*ChainContext\rgpChain + i * 4)
Debug "ChainElements: " + Str(*simpleCertificateChainWithinContext\cElement)
; For each certificate chain in this context...
For simpleCertChainIndex = 0 To *simpleCertificateChainWithinContext\cElement - 1
Debug ""
Debug "ChainElement " + Str(simpleCertChainIndex + 1)
; get the CertContext from the Array
*SimpleChain = PeekL(*simpleCertificateChainWithinContext\rgpElement + simpleCertChainIndex * 4)
*CertContext = *SimpleChain\CertContext
;-------------------------------------------------------------------
; Find And print the name of the subject of the certificate
; just retrieved.
*NameString = AllocateMemory(128)
If *NameString
If CertGetNameString(*CertContext, #CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, #Null, *NameString, 128)
Debug "Certificate for " + PeekS(*NameString) + " has been retrieved"
Else
Debug "CertGetName failed."
EndIf
FreeMemory(*NameString)
EndIf
; Get the issuer now...
*NameString = AllocateMemory(128)
If *NameString
If CertGetNameString(*CertContext, #CERT_NAME_SIMPLE_DISPLAY_TYPE, #CERT_NAME_ISSUER_FLAG, #Null, *NameString, 128)
Debug "Certificate issuer is " + PeekS(*NameString)
Else
Debug "CertGetName failed."
EndIf
FreeMemory(*NameString)
EndIf
Next simpleCertChainIndex
Next i
CertFreeCertificateChain(*CertCtx)
Else
Debug "InternetQueryOption Error: " + Str(GetLastError_())
EndIf
Else
Debug "HTTPSendRequest Error: " + Str(GetLastError_())
EndIf
Else
Debug "HttpOpenRequest Error: " + Str(GetLastError_())
EndIf
Else
Debug "InternetConnect Error: " + Str(GetLastError_())
EndIf
Else
Debug "InternetOpen Error: " + Str(GetLastError_())
EndIf
The Problem was: pointer to pointer array
In PB we have to receive the correct entries 'by hand'
When you use 64bit version of PB you have to adjust some things...
Bernd
Re: How to download SSL certificate from a server
Posted: Sat Nov 10, 2018 5:09 pm
by firace
Wow, that's an amazing job.
You are the KING of WINAPI.
Now I will study the code...
Thanks again!
Re: How to download SSL certificate from a server
Posted: Sat Nov 10, 2018 5:29 pm
by infratec
No, that's definately Rashad
Re: How to download SSL certificate from a server
Posted: Tue Feb 18, 2020 3:55 pm
by tatanas
Sorry to dig up this topic but I'm stucked with a certificate problem with httprequest(). (
viewtopic.php?f=13&t=74640)
I would like to download the certificate of a switch. I found your code infratec but as you said, it needs some adjustments to work with 64bits PB and I don't know what variable or Peek I should modify.
Could you tell me what I should change ?
Thanks.
Re: How to download SSL certificate from a server
Posted: Tue Feb 18, 2020 4:17 pm
by firace
tatanas wrote:Sorry to dig up this topic but I'm stucked with a certificate problem with httprequest(). (
viewtopic.php?f=13&t=74640)
I would like to download the certificate of a switch. I found your code infratec but as you said, it needs some adjustments to work with 64bits PB and I don't know what variable or Peek I should modify.
Could you tell me what I should change ?
Thanks.
Infratec kindly provided a 64-bit solution here:
viewtopic.php?f=12&t=71727