【问题标题】:Can not programmatically determine which TLS version my app uses无法以编程方式确定我的应用使用的 TLS 版本
【发布时间】:2017-05-02 11:01:16
【问题描述】:

简介:

我想以编程方式确定我的应用程序在与服务器通信时使用的 TLS 版本。

应用程序是用 C++ 编写的,使用 WinInet。

我为解决这个问题所做的努力:

由于INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT 标志,我找到了InternetQueryOption 这似乎是解决方案。

问题:

当合并到我的应用程序中时,InternetQueryOption 会填充 INTERNET_CERTIFICATE_INFO 结构。

问题是结构的lpszProtocolName是空的,所以我看不到使用的是哪个协议。

下面是说明问题的MVCE

#include <Windows.h>
#include <iostream>
#include <WinInet.h>
#include <string>

#pragma comment(lib, "Wininet.lib")

int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        std::cout << "Enter HTTPS address for test" << std::endl;
        return -1;
    }

    URL_COMPONENTS urlComp;
    ::ZeroMemory(&urlComp, sizeof(URL_COMPONENTS));
    urlComp.dwStructSize = sizeof(URL_COMPONENTS);
    urlComp.dwHostNameLength = -1;
    urlComp.dwSchemeLength = -1;
    urlComp.dwUrlPathLength = -1;

    if (!::InternetCrackUrl(argv[1], strlen(argv[1]), 0, &urlComp))
    {
        std::cout << "#0 " << ::GetLastError() << std::endl;
        return -1;
    }

    if (INTERNET_SCHEME_HTTPS != urlComp.nScheme)
    {
        std::cout << "#1 " << ::GetLastError() << std::endl;
        return -1;
    }

    HINTERNET hIntSession = ::InternetOpen("WinInet", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);

    if (NULL == hIntSession)
    {
        std::cout << "#2 " << ::GetLastError() << std::endl;
        return -1;
    }

    std::string s(strlen(argv[1]), 0);
    ::memcpy(&s[0], urlComp.lpszHostName, urlComp.dwHostNameLength);

    HINTERNET hHttpSession = ::InternetConnect(hIntSession, s.c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0, 0, INTERNET_SERVICE_HTTP, 0, NULL);

    if (NULL == hHttpSession)
    {
        std::cout << "#3 " << ::GetLastError() << std::endl;
        ::InternetCloseHandle(hIntSession);
        return -1;
    }

    HINTERNET hHttpRequest = ::HttpOpenRequest(hHttpSession, "HEAD", NULL, 0, 0, 0, INTERNET_FLAG_SECURE, 0);

    if (NULL == hHttpRequest)
    {
        std::cout << "#4 " << ::GetLastError() << std::endl;
        ::InternetCloseHandle(hHttpSession);
        ::InternetCloseHandle(hIntSession);
        return -1;
    }

    if (!::HttpSendRequest(hHttpRequest, NULL, 0, NULL, 0)) 
    {
        std::cout << "#5 " << ::GetLastError() << std::endl;
        ::InternetCloseHandle(hHttpRequest);
        ::InternetCloseHandle(hHttpSession);
        ::InternetCloseHandle(hIntSession);
        return -1;
    }

    INTERNET_CERTIFICATE_INFO certificateInfo;
    DWORD certInfoLength = sizeof(INTERNET_CERTIFICATE_INFO);

    if (!::InternetQueryOption(hHttpRequest, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT, &certificateInfo, &certInfoLength))
    {
        std::cout << "#6 " << ::GetLastError() << std::endl;
        ::InternetCloseHandle(hHttpRequest);
        ::InternetCloseHandle(hHttpSession);
        ::InternetCloseHandle(hIntSession);
        return -1;
    }

    if (certificateInfo.lpszProtocolName)
    {
        std::cout << certificateInfo.lpszProtocolName << std::endl;
        ::LocalFree(certificateInfo.lpszProtocolName);
    }

    ::InternetCloseHandle(hHttpRequest);
    ::InternetCloseHandle(hHttpSession);
    ::InternetCloseHandle(hIntSession);

    return 0;
}

问题:

由于这是我第一次使用带有上述标志的 API,我相信我做错了什么。

您能帮我更正 MVCE 以便我查看使用了哪个版本的 TLS 吗?

【问题讨论】:

    标签: c++ ssl tls1.2 wininet


    【解决方案1】:

    Wininet 有许多扩展功能、选项和结构,这些功能、选项和结构在 MSDN 中没有记录,但仅适用于标准 wininet 旁边的 winineti.h(注意结尾的 'i')头文件。 h 文件。您不需要任何外部库,它们由 wininet.dll 实现(并且可用于在 wininet.lib 中链接)。

    您将对INTERNET_OPTION_SECURITY_CONNECTION_INFO 选项特别感兴趣,该选项应该可以满足您的需求。

    你必须传递一个指向 INTERNET_SECURITY_CONNECTION_INFO 结构的指针。该结构包含一个类型为SecPkgContext_ConnectionInfo 的connectionInfo 字段,该字段已被完整记录。这个结构实际上是由 SSPI/Schannel 定义的,Wininet 内部使用它来处理所有低级协议工作。

    这是一个示例代码,您可以将其添加到现有代码中:

    INTERNET_SECURITY_CONNECTION_INFO connInfo = { 0 };
    DWORD certInfoLength = sizeof(INTERNET_SECURITY_CONNECTION_INFO);
    InternetQueryOption(hHttpRequest, INTERNET_OPTION_SECURITY_CONNECTION_INFO, &connInfo, &certInfoLength);
    
    // now, connInfo.connectionInfo should contain all you need
    

    【讨论】:

    • 谢谢你,我很快就会奖励赏金。 +1
    • 最小赏金期已过,因此我已按承诺授予赏金。再次感谢。下次再见!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多