Дополнительно к предыдущему ответу.
Если вы хотите вручную проверять сертификаты с ненадежным корнем (например, с собственной подписью), вам нужно
1) Установить флаги, чтобы игнорировать недоверенные сертификаты
// Open request before
HINTERNET hRequest = HttpOpenRequest(hConnect, _T("POST"), action, NULL, NULL, NULL, dwFlags, 0);
if (!hRequest) return GetLastError();
// set ignore options to request
DWORD dwFlags;
DWORD dwBuffLen = sizeof(dwFlags);
InternetQueryOption(hRequest, INTERNET_OPTION_SECURITY_FLAGS, (LPVOID)&dwFlags, &dwBuffLen);
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOption (hRequest, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags));
2) Отправить запрос данных
If(HttpSendRequest(hRequest, strHeaders, strHeaders.GetLength(), data, len)) {
3) И только после возврата запроса данных мы можем просмотреть информацию о сертификате и проверить отпечаток.
Чтобы получить отпечаток, мы должны использовать методы из cryptapi,
поэтому необходимо #include "WinCrypt.h" и добавить crypt32.lib в компоновщик
PCCERT_CHAIN_CONTEXT CertCtx=NULL;
DWORD cbCertSize = sizeof(&CertCtx);
// Get certificate chain information
if (InternetQueryOption(hRequest, INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT, (LPVOID)&CertCtx, &cbCertSize))
{
PCCERT_CHAIN_CONTEXT pChainContext=CertCtx;
CERT_SIMPLE_CHAIN *simpleCertificateChainWithinContext = NULL;
for (int i=0; i<pChainContext->cChain; i++)
{
simpleCertificateChainWithinContext=pChainContext->rgpChain[i];
// We can check any certificates from chain, but if selfsigned it will be single
for (int simpleCertChainIndex = 0; simpleCertChainIndex < simpleCertificateChainWithinContext->cElement; impleCertChainIndex++)
{
// get the CertContext from the array
PCCERT_CONTEXT pCertContext = simpleCertificateChainWithinContext->rgpElement[simpleCertChainIndex]->pCertContext;
// Public key can be getted from
// (((*((*pCertContext).pCertInfo)).SubjectPublicKeyInfo).PublicKey).pbData
// but better to use thumbprint to check
// CERT_HASH_PROP_ID - is a thumbprint
BYTE thumbprint[1024];
DWORD len = 1024;
if(CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID, thumbprint, &len)) {
//
// !!! HERE WE CAN CHECK THUMPRINT WITH TRUSTED(PREVIOUSLY SAVED)
// and return error, or accept request output.
//
}
}
}
// important! Free the CertCtx
CertFreeCertificateChain(CertCtx);
}
4) Зачем использовать отпечаток пальца для сравнения сертификата?
В сертификате есть три интересных поля для сравнения:
Серийный номер, Открытый ключ, Отпечаток пальца.
Серийный номер - это просто уникальный номер, выбранный центром сертификации, выдавшим сертификат,
открытый ключ хорошее решение, но отпечаток большого пальца вычисляется по хешу по всему сертификату
(https://security.stackexchange.com/questions/35691/what-is-the-difference-between-serial-number-and-thumbprint)