可以通過 openssl 獲取常規的,但是部分網站獲取不正確。
// 請使用 CertFreeCertificateContext 釋放 *p_context
void GetCertFromDomain(const wchar_t* domain, int nPort, CERT_CONTEXT** p_context)
{
if (NULL == domain || NULL == p_context)
{
return;
}
static HINTERNET hsession = NULL;
HINTERNET hconnect = NULL;
HINTERNET _request = NULL;
do
{
BOOL bRet = FALSE;
DWORD dwTime = 5;
if (NULL == hsession)
{
hsession = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
}
if (NULL == hsession)
{
break;
}
hconnect = WinHttpConnect(hsession, domain, nPort, 0);
if (NULL == hconnect)
{
break;
}
bRet = WinHttpSetTimeouts(hsession, 2000, 2000, 2000, 2000);
_request = WinHttpOpenRequest(hconnect, NULL, L"/", NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE);
if (NULL == _request)
{
break;
}
bRet = WinHttpSendRequest(_request,
WINHTTP_NO_ADDITIONAL_HEADERS,
0, WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
if (bRet)
{
DWORD len = 4;
WCHAR* pBuff = NULL;
if (!WinHttpQueryOption(_request, WINHTTP_OPTION_SERVER_CERT_CONTEXT,
&pBuff, &len))
{
break;
}
*p_context = (CERT_CONTEXT*)pBuff;
if (!*p_context)
{
break;
}
}
} while (0);
if (_request)
WinHttpCloseHandle(_request);
if (hconnect)
WinHttpCloseHandle(hconnect);
if (hsession)
WinHttpCloseHandle(hsession);
}
int main(int argc, char* argv[])
{
CERT_CONTEXT* p_context = NULL;
GetCertFromDomain(L"jd.com", 443, &p_context);
{
X509* x = NULL;
GENERAL_NAMES* subjectAltNames = NULL;
std::list<std::string> lstHosts;
do
{
x = d2i_X509(NULL, (const unsigned char**)&p_context->pbCertEncoded, p_context->cbCertEncoded);
if (NULL == x)
{
break;
}
subjectAltNames = (GENERAL_NAMES*)X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
if (NULL == subjectAltNames)
{
break;
}
int count = sk_GENERAL_NAME_num(subjectAltNames);
for (int i = 0; i < count; i++)
{
GENERAL_NAME* gen = sk_GENERAL_NAME_value(subjectAltNames, i);
if (gen->type == GEN_URI || gen->type == GEN_DNS || gen->type == GEN_EMAIL)
{
ASN1_IA5STRING* asn1_str = gen->d.uniformResourceIdentifier;
// OutputDebugStringA((char*)ASN1_STRING_data(asn1_str));//,ASN1_STRING_length(asn1_str));
std::string strTmp;
strTmp.append((char*)ASN1_STRING_data(asn1_str), ASN1_STRING_length(asn1_str));
lstHosts.push_back(strTmp);
}
}
break;
} while (0);
if (subjectAltNames)
{
GENERAL_NAMES_free(subjectAltNames);
}
if (x)
{
X509_free(x);
}
CertFreeCertificateContext(p_context);
}
return 0;
}