代码之家  ›  专栏  ›  技术社区  ›  galets

在wininet中手动验证服务器证书

  •  2
  • galets  · 技术社区  · 16 年前

    我正在尝试对wininet客户端实现手动自签名ssl证书验证。我试图通过打电话来接近它 InternetQueryOption 具有 INTERNET_OPTION_SECURITY_CERTIFICATE INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT 参数,但都返回一些服务器证书的内部解释,没有一个允许访问原始证书公钥或至少thumbprimnt。

    如何验证证书?…

    2 回复  |  直到 16 年前
        1
  •  2
  •   Community Mohan Dere    8 年前

    除了前面的回答。 如果要手动检查具有不受信任根(例如自签名)的证书,则需要

    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中的方法, 所以需要包含“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)为什么使用指纹来比较证书? 证书中有三个有趣的字段要比较: 序列号,公钥,指纹。 序列号只是颁发证书的CA选择的唯一编号, 公钥很好的解决方案,但指纹是在完整证书上计算的哈希值 ( https://security.stackexchange.com/questions/35691/what-is-the-difference-between-serial-number-and-thumbprint )

        2
  •  0
  •   2 revs<br/>Temich&#13;    16 年前

    如果在调用httpopenrequest时设置internet标志安全,wininet将已经验证返回的证书的域名是否与证书匹配,并且证书链是可信的。

    之后你可以做的事情很少:

    1. 使用Internet选项安全证书结构的lpszissuerinfo将返回的域名和证书名与预期的父证书匹配进行比较。

    2. 从lpszissuerinfo中分析出颁发者名称,并调用certfindcertificateeinstore以获取证书上下文指针。

    3. 使用certgetcertificatechain和证书上下文指针获取并验证证书链,例如比较颁发证书的指纹,但不比较据我所知的实际证书本身。

    供将来参考,来自msdn:“ http://msdn.microsoft.com/en-us/library/aa385328(VS.85).aspx “。如果安装了IE8.0,则会有一个新选项公开服务器的证书链。

    Internet选项服务器证书链上下文 一百零五

    将服务器证书链上下文检索为重复的pccert_chain_上下文。您可以将此重复上下文传递给任何接受pccert_chain_context的crypto api函数。处理完证书链上下文后,必须在返回的pccert_chain_上下文上调用certfreecertificatechain。

    版本:需要Internet Explorer 8.0。

    推荐文章