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 "Main.h"
#include <winhttp.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 hSession = NULL;
HINTERNET hConnect = NULL; HINTERNET hConnect = NULL;
@ -54,10 +68,14 @@ BOOL HTTPGetFile (CTSTR url, CTSTR outputPath, CTSTR extraHeaders, int *response
if (urlComponents.nPort == 443) if (urlComponents.nPort == 443)
secure = TRUE; secure = TRUE;
retry:
hSession = WinHttpOpen(OBS_VERSION_STRING, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); hSession = WinHttpOpen(OBS_VERSION_STRING, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession) if (!hSession)
goto failure; 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); hConnect = WinHttpConnect(hSession, hostName, secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0);
if (!hConnect) if (!hConnect)
goto failure; 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); BOOL bResults = WinHttpSendRequest(hRequest, extraHeaders, extraHeaders ? -1 : 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
// End the request. if (!bResults)
if (bResults) {
bResults = WinHttpReceiveResponse(hRequest, NULL); DWORD err = GetLastError();
else if (err == ERROR_WINHTTP_SECURE_FAILURE && invalidCN && h && h())
{
secure = 0;
WinHttpSetStatusCallback(hSession, nullptr, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, NULL);
goto retry;
}
goto failure; goto failure;
}
// End the request.
bResults = WinHttpReceiveResponse(hRequest, NULL);
TCHAR statusCode[8]; TCHAR statusCode[8];
DWORD statusCodeLen; DWORD statusCodeLen;
@ -121,7 +148,10 @@ BOOL HTTPGetFile (CTSTR url, CTSTR outputPath, CTSTR extraHeaders, int *response
failure: failure:
if (hSession) if (hSession)
{
WinHttpSetStatusCallback(hSession, nullptr, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, NULL);
WinHttpCloseHandle(hSession); WinHttpCloseHandle(hSession);
}
if (hConnect) if (hConnect)
WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hConnect);
if (hRequest) if (hRequest)

View File

@ -19,6 +19,8 @@
#pragma once #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); 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 MANIFEST_URL "https://builds.catchexception.org/update.json"
#define UPDATER_PATH "/updates/org.catchexception.builds.updater.exe" #define UPDATER_PATH "/updates/org.catchexception.builds.updater.exe"
#define UPDATE_CHANNEL "master" #define UPDATE_CHANNEL "master"
*/ //*/
#ifndef MANIFEST_WITH_ARCHIVES #ifndef MANIFEST_WITH_ARCHIVES
#define MANIFEST_WITH_ARCHIVES 0 #define MANIFEST_WITH_ARCHIVES 0
@ -372,6 +372,11 @@ bool ParseUpdateManifest (TCHAR *path, BOOL *updatesAvailable, String &descripti
#endif #endif
} }
bool Win81TLSSNIBugHandler()
{
return OSGetVersion() == 8 && OBSMessageBox(hwndMain, Str("Updater.Win81TLSSNIBug"), nullptr, MB_YESNOCANCEL | MB_DEFBUTTON2) == IDYES;
}
DWORD WINAPI CheckUpdateThread (VOID *arg) DWORD WINAPI CheckUpdateThread (VOID *arg)
{ {
int responseCode; int responseCode;
@ -421,7 +426,11 @@ DWORD WINAPI CheckUpdateThread (VOID *arg)
scat(extraHeaders, strGUID); 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)) if (HTTPGetFile(TEXT(MANIFEST_URL), manifestPath, extraHeaders, &responseCode))
#endif
{ {
if (responseCode == 200 || responseCode == 304) 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.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.UpdatesAvailable="Updates are available"
Updater.NoUpdatesAvailable="No 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.LogFiles="Log Files"
MainMenu.Help.AnalyzeCurrentLog="Analyze current Log File" MainMenu.Help.AnalyzeCurrentLog="Analyze current Log File"