我正在尝试对 WinINet 客户端实施手动自签名 SSL 证书验证。我尝试通过InternetQueryOption
使用 INTERNET_OPTION_SECURITY_CERTIFICATE
或INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT
参数调用来解决它,但两者都返回服务器证书的一些内部解释,没有一个允许访问原始证书公钥或至少是 thumbprimnt。
我应该如何验证证书?...
除了先前的答案。如果您想手动检查具有不受信任的根的证书(例如自签名),您需要
// 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));
if (HttpSendRequest(hRequest, strHeaders, strHeaders.GetLength(), data, len)) {
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);
}
如果您在调用 HttpOpenRequest 时设置了 INTERNET_FLAG_SECURE,WinInet 将已经验证返回的证书的域名是否与证书匹配并且证书链是受信任的。
之后你可以做的几件事:
使用 INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT 的 lpszIssuerInfo 将返回的域名和证书名称与预期的父证书进行比较。
从 lpszIssuerInfo 中解析出颁发者名称并调用 CertFindCertificateInStore 以获取证书上下文指针。
使用 CertGetCertificateChain 和证书上下文指针获取和验证证书链,例如比较颁发证书的指纹,但不是我所知道的实际证书本身。
供将来参考,来自 MSDN:“ http://msdn.microsoft.com/en-us/library/aa385328(VS.85).aspx ”。如果安装了 IE8.0,则有一个公开服务器证书链的新选项。
INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT 105
检索服务器的证书链上下文作为重复的 PCCERT_CHAIN_CONTEXT。您可以将此重复的上下文传递给任何采用 PCCERT_CHAIN_CONTEXT 的 Crypto API 函数。完成证书链上下文后,您必须在返回的 PCCERT_CHAIN_CONTEXT 上调用 CertFreeCertificateChain。
版本:需要 Internet Explorer 8.0。