Add workaround for broken TLS SNI in Windows 8.1 for the archive updater

Asking users to download update (manifests) via an insecure connection is not
ideal, but considering most of them downloaded the original test build via an
insecure connection in the first place it might be ok

Unfortunately the detection is not perfect, so genuine TLS attacks can be
misinterpreted as the bug; completely invalid/expired/otherwise broken
certificates should be rejected though
This commit is contained in:
palana 2014-03-05 16:04:02 +01:00
parent 3d468a2364
commit 9b657018c6
4 changed files with 49 additions and 7 deletions

View File

@ -20,7 +20,21 @@
#include "Main.h"
#include <winhttp.h>
BOOL HTTPGetFile (CTSTR url, CTSTR outputPath, CTSTR extraHeaders, int *responseCode)
__declspec(thread) bool invalidCN = false;
static void CALLBACK WinHTTPStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength)
{
if (dwStatusInformationLength != 4)
return;
if ((*(DWORD*)lpvStatusInformation) & ~(WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID | WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA))
return;
if ((*(DWORD*)lpvStatusInformation) & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID)
invalidCN = true;
}
BOOL HTTPGetFile(CTSTR url, CTSTR outputPath, CTSTR extraHeaders, int *responseCode, HTTPGetFileWin81TLSSNIBugHandler h)
{
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
@ -54,10 +68,14 @@ BOOL HTTPGetFile (CTSTR url, CTSTR outputPath, CTSTR extraHeaders, int *response
if (urlComponents.nPort == 443)
secure = TRUE;
retry:
hSession = WinHttpOpen(OBS_VERSION_STRING, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession)
goto failure;
if (secure)
WinHttpSetStatusCallback(hSession, WinHTTPStatusCallback, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, NULL);
hConnect = WinHttpConnect(hSession, hostName, secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0);
if (!hConnect)
goto failure;
@ -68,11 +86,20 @@ BOOL HTTPGetFile (CTSTR url, CTSTR outputPath, CTSTR extraHeaders, int *response
BOOL bResults = WinHttpSendRequest(hRequest, extraHeaders, extraHeaders ? -1 : 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
// End the request.
if (bResults)
bResults = WinHttpReceiveResponse(hRequest, NULL);
else
if (!bResults)
{
DWORD err = GetLastError();
if (err == ERROR_WINHTTP_SECURE_FAILURE && invalidCN && h && h())
{
secure = 0;
WinHttpSetStatusCallback(hSession, nullptr, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, NULL);
goto retry;
}
goto failure;
}
// End the request.
bResults = WinHttpReceiveResponse(hRequest, NULL);
TCHAR statusCode[8];
DWORD statusCodeLen;
@ -121,7 +148,10 @@ BOOL HTTPGetFile (CTSTR url, CTSTR outputPath, CTSTR extraHeaders, int *response
failure:
if (hSession)
{
WinHttpSetStatusCallback(hSession, nullptr, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, NULL);
WinHttpCloseHandle(hSession);
}
if (hConnect)
WinHttpCloseHandle(hConnect);
if (hRequest)

View File

@ -19,6 +19,8 @@
#pragma once
BOOL HTTPGetFile (CTSTR url, CTSTR outputPath, CTSTR extraHeaders, int *responseCode);
typedef bool(HTTPGetFileWin81TLSSNIBugHandler)();
BOOL HTTPGetFile(CTSTR url, CTSTR outputPath, CTSTR extraHeaders, int *responseCode, HTTPGetFileWin81TLSSNIBugHandler h = nullptr);
String CreateHTTPURL(String host, String path, String extra=String(), bool secure=false);

View File

@ -99,7 +99,7 @@ BOOL CalculateFileHash (TCHAR *path, BYTE *hash)
#define MANIFEST_URL "https://builds.catchexception.org/update.json"
#define UPDATER_PATH "/updates/org.catchexception.builds.updater.exe"
#define UPDATE_CHANNEL "master"
*/
//*/
#ifndef MANIFEST_WITH_ARCHIVES
#define MANIFEST_WITH_ARCHIVES 0
@ -372,6 +372,11 @@ bool ParseUpdateManifest (TCHAR *path, BOOL *updatesAvailable, String &descripti
#endif
}
bool Win81TLSSNIBugHandler()
{
return OSGetVersion() == 8 && OBSMessageBox(hwndMain, Str("Updater.Win81TLSSNIBug"), nullptr, MB_YESNOCANCEL | MB_DEFBUTTON2) == IDYES;
}
DWORD WINAPI CheckUpdateThread (VOID *arg)
{
int responseCode;
@ -421,7 +426,11 @@ DWORD WINAPI CheckUpdateThread (VOID *arg)
scat(extraHeaders, strGUID);
}
#if MANIFEST_WITH_ARCHIVES
if (HTTPGetFile(TEXT(MANIFEST_URL), manifestPath, extraHeaders, &responseCode, Win81TLSSNIBugHandler))
#else
if (HTTPGetFile(TEXT(MANIFEST_URL), manifestPath, extraHeaders, &responseCode))
#endif
{
if (responseCode == 200 || responseCode == 304)
{

View File

@ -381,6 +381,7 @@ Updater.NewUpdates="The following updates are available:\r\n\r\n"
Updater.RunningWarning="OBS will be restarted to install the updates.\r\n\r\nAre you sure you want to continue?"
Updater.UpdatesAvailable="Updates are available"
Updater.NoUpdatesAvailable="No updates are available"
Updater.Win81TLSSNIBug="Due to a bug in Windows 8.1 the secure update check failed. Do you want to retry the update check via an insecure connection?"
MainMenu.Help.LogFiles="Log Files"
MainMenu.Help.AnalyzeCurrentLog="Analyze current Log File"