无法以编程方式确定我的应用程序使用哪个 TLS 版本
Can not programmatically determine which TLS version my app uses
简介:
我想以编程方式确定我的应用程序在与服务器通信时使用的 TLS 版本。
应用程序是用 C++ 编写的,使用 WinInet。
我为解决这个问题所做的努力:
我找到了 InternetQueryOption which seemed like the solution due to INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT 标志。
问题:
当合并到我的应用程序中时,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 吗?
Wininet 有一堆扩展函数、选项和结构,这些函数、选项和结构在 MSDN 中没有记录,但只有 winineti.h
(注意结尾 'i')头文件才可用,应该是将标准 wininet.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
简介:
我想以编程方式确定我的应用程序在与服务器通信时使用的 TLS 版本。
应用程序是用 C++ 编写的,使用 WinInet。
我为解决这个问题所做的努力:
我找到了 InternetQueryOption which seemed like the solution due to INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT 标志。
问题:
当合并到我的应用程序中时,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 吗?
Wininet 有一堆扩展函数、选项和结构,这些函数、选项和结构在 MSDN 中没有记录,但只有 winineti.h
(注意结尾 'i')头文件才可用,应该是将标准 wininet.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