2016-12-16 37 views
1

簡介:

我想以編程方式確定使用哪個TLS版本我的應用程序與服務器進行通信時。不能以編程方式確定哪個版本的TLS我的應用程序使用

應用程序使用WinInet以C++編寫。

我的努力解決這個問題:

我發現InternetQueryOption這似乎是解決由於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已被使用?

回答

1

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 
+0

謝謝你,我將獎勵獎金很快。 +1 – AlwaysLearningNewStuff

+0

最小賞金期限已過,因此我已按照承諾授予賞金。再次感謝。最好的問候,直到下一次! – AlwaysLearningNewStuff

相關問題